views:

145

answers:

5

take following class and two object definitions:

class Rect{
 public:
  enum centimeter;
  enum meter;
  Rect(double len,double wid,enum centimeter){
   length=(len/100);
   width=(wid/100);
  }
  Rect(int len,int wid,enum meter){
   length=len;
   width=wid;
  }
  //rest of implementation
 private:
  double length;//in meters
  double width;//in meters
};
Rect obj1(10,5,Rect::centimeter());
Rect obj2(10,5,Rect::meter());

two previous constructors have dummy enum parameters to solve calling ambiguity caused in case these dummy parameters didn't exist. Now in spite of possibility of using named constructors here, if I insist on using these dummy parameters, does this violate any coding rule that I should be aware of ?

+10  A: 

I think it violates my taste. I would code it like this:

enum Unit {
  Centimeter = 100, 
  Meter      = 1
};

Rect(int len, int wid, Unit unit) {
  length = len / (int) unit;
  width = wid / (int) unit;
}

Rect obj1(10, 5, Rect::Centimeter);
Rect obj2(10, 5, Rect::Meter);
Johannes Schaub - litb
@litb: you make a good point. But when the extra param is a type, often a compile time decision can be made (since it is calling a separate constructor based on the params type). Of course this is nothing you don't already know ;) and in this case I prefer the method you suggest here since it is simply choosing units.
Evan Teran
+1  A: 

Can't say this breaks a rule, but... It isn't easy to read.

Why can't you declare a

enum metrics {
  centimeter,
  meter
};

and use it as the constructor parameter? Or it can be

class Rect {
public:
  static Rect CreateWithMeters(int width, int height);
  static Rect CreateWithCentimenets(int width, int height);
}

Either is better than current code at my taste.

Gobra
+1  A: 

STL uses that idiom to differentiate iterator types in lieu of concepts.

MSN
Can you point to a concrete example?
David Rodríguez - dribeas
@David: I think MSN refers to those where common implementations _internally_ use default arguments like `std::iterator_traits<It>::iterator_category` in order to differentiate between iterator pairs and two `int` (as in `std::vector<int> v(0,0);`). However, I think a better example from the std lib would be `new(std::nothrow)`.
sbi
A: 
Rect(int len,int wid,enum centimeter){
  length=(len/100);
  width=(wid/100);
}

In addition to what others wrote, this logic is bad, because Rect(99,99,Rect::centimeter()) is equal to Rect(0,0,Rect::centimeter()).

If you are storing meters internally, do not provide an interface with centimetres, not this way nor any other way.

zvonimir
I took care of it, shouldn't have taken integer as type of parameters of the constructor that has a parameter of centimeter enum type, changed it to double.
Pooria
Doesn't particularly help, the fractional meters are still discarded.
Ben Voigt
You should change the private variables as well or it won't help much. Of course, then you should change the other constructor for consistency.
zvonimir
Well, 0-99cm _are_ 0m, that's just the way it is when you round to the nearest meter.
sbi
changed type of private variables to double, not to get numbers rounded.
Pooria
It's not 0m, it's 0.99m
Johannes Schaub - litb
+3  A: 

BOOST_STRONG_TYPEDEF could be the answer here.

BOOST_STRONG_TYPEDEF( double, Meter )
BOOST_STRONG_TYPEDEF( double, Centimeters)
BOOST_STRONG_TYPEDEF( double, Furlongs)

class Rect
{
 public:
  Rect(Meter len, Meter wid) : length(len), width(wid) 
  {};

  Rect(Centimeter len, Centimeter wid) : length(len/100), width(wid/100) 
  {};
}

Rect obj1(Meter(10),Meter(5));
Rect obj1(Centimeter(10),Centimeter(5));
Roddy