
Hi Andrey -
I haven't read any docs or seen the library. Just a thought on spot. May be a cast-like synax would be more natural here?
quantity< double, SI::length > q1 = quantity_cast< SI::length >(1.5); quantity< int, SI::length > q2 = quantity_cast< SI::length >(100);
I like the idea of quantity_cast, being partial to making anything potentially dangerous be easily identified in code - I think a similar syntax could be used for three different use cases: 1) construction from a value_type: template<class Y,class Unit> quantity<Y,Unit> quantity_cast(const Y&); 2) casting to a different value_type: template<class Y,class Z,class Unit> quantity<Y,Unit> quantity_cast(const quantity<Z,Unit>&) and 3) casting to a different unit system template<class Y,class System1,class System2,class Dim> quantity<Y,unit<System2,Dim> > quantity_cast(const quantity<Y,unit<System1,Dim> >&) This should be relatively easy to implement...(famous last words)
And construction with no explicit casting but via explicit constructor should be possible too:
quantity< double, SI::length > q1(1.5); quantity< int, SI::length > q2(100);
My paradigm in designing this library is to be able to 1) prevent the Mars Climate Orbiter disasters and 2) to facilitate changing of unit systems in code with maximal safety. My concern with having an explicit constructor with only a value_type argument is that someone who decided to change from SI to CGS systems could easily forget to update the constructor arguments : quantity<double,SI::length> q1(1.0); // 1 meter would get changed to quantity<double,CGS::length> q1(1.0); // 1 centimeter with no indication that there was any problem. If we allow explicit unit system conversion, this change would behave as expected: quantity<double,SI::length> q1(1.0*meter); // 1 meter becomes quantity<double,CGS::length> q1(1.0*meter); // 100 centimeters and, therefore, be safe. The same is true if we require quantity_cast for unit system conversion.
And this IMO should go implicitly:
// Conversion from int to double via assignment q1 = q2;
I'm not a big lover of implicit type conversion. This is again an issue of maximizing the safety of using quantities. If we allow implicit value_type conversions, we permit truncation in cases of things like double->int. Preventing this does add one more layer of safety netting. On the other hand, there is something to be said for having quantities simply delegate their value_type conversions to the value_type itself - I guess I'm happy to go either way, depending on the consensus...
And quantity conversion should require explicit casting:
quantity< double, SI::centigrade > q4; quantity< double, SI::kelvin > q5; q5 = quantity_cast< SI::kelvin >(q4);
Of course, the centigrade<->kelvin issue opens a new can of worms since that conversion is affine, not linear. At present, this conversion is not implemented in the library. My preference would be to define a value_type that models a unit with offset that could be converted to linear value_types... Right now, the library allows implicit unit system conversions (as described above), and, with quantity_cast, would allow casting as well.
PS: And another couple of cents. Maybe the representation type of "quantity" template should be optional defaulted to double or, the better way, to the type that is natural for the quantity type. I.e., for "SI::length" the "double" would be natural.
Paul Bristow has brought this up, too. I really, really wish there was a template typedef facility. Lacking that, I'm inclined to define, in the boost::units::SI namespace, another quantity class that defaults to the SI system and double precision value_type. This could invert the order of template arguments, too: namespace SI { template<class Unit,class Y = double> class quantity : public boost::units::quantity<Y,Unit> { ... }; } Thanks for the input. Matthias