
Hello Matthias, Tuesday, January 16, 2007, 7:23:44 AM, you wrote: [snip]
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.
Well, maybe you're right here.
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...
IMHO, such implicit conversions would be more natural for users (for me at least). Of course, such conversions should be valid only if these representation types are implicitly convertible (a user may ensure they are not, if it's necessary). And if there is a percision loss on such conversion, a well-mannered compiler will issue a warning.
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.
My humble knowledge may have confused me but I thought that the same temperature by Centigrade and by Kelvin will always differ by about 273 (i.e. the conversion is linear). Which is not right in case of Farenheit.
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.
Maybe the library should offer an opportunity to extend the out of box set of supported quantities. If you agree with me here, there should be a way of specifying user-defined quantities and conversion rules between them. I see it something like this: template< typename FromT, typename ToT > struct conversion_rule; template< > struct conversion_rule< unit< SI::kelvin, SI::grade >, unit< SI::centigrade, SI::grade >
{ template< typename T > static T apply(T const& value) { return value - 273; } }; template< > struct conversion_rule< unit< SI::centigrade, SI::grade >, unit< SI::kelvin, SI::grade >
{ template< typename T > static T apply(T const& value) { return value + 273; } }; template< class System2, class System1, class Dim, class Y > quantity< Y, unit< System2, Dim > > quantity_cast(const quantity< Y, unit< System1, Dim > >& from) { typedef conversion_rule< unit< System1, Dim >, unit< System2, Dim >
conversion_rule_t; return conversion_rule::apply(from.get()); // here acquire the // actual value of the quantity, it'll be of type Y }
Although the structures as the conversion rules is not the best way to implement it (making use of free functions for this purpose would be more flexible because of ADL involvement), the main idea is to extract the conversion algorithm to a user-defined entity.
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> { ... };
}
As it was mentioned by Peder Holt, it is quite possible to make these template parameters irrelevant of the position. I'd do something like that: struct unit_base {}; template< typename T1, typename T2 > struct unit : public unit_base { }; template< typename T > struct is_unit : public is_base_and_derived< T, unit_base > {}; // Double bool check is required to detect erroneous quantity // instantiations template< typename T1, typename T2, bool = is_unit< T1 >::value, bool = is_unit< T2 >::value
struct quantity_tmplt_params; template< typename T1, typename T2 > struct quantity_tmplt_params< T1, T2, true, false > { typedef T1 unit_type; typedef typename mpl::if_< is_same< T2, void >, typename unit_type::default_value_type, T2
::type value_type; };
template< typename T1, typename T2 > struct quantity_tmplt_params< T1, T2, false, true > { typedef T2 unit_type; typedef typename mpl::if_< is_same< T1, void >, typename unit_type::default_value_type, T1
::type value_type; };
// It's better to use void for defaults as it shortens mangled names template< typename T1, typename T2 = void > class quantity : public quantity_impl< typename quantity_tmplt_params< T1, T2 >::value_type, typename quantity_tmplt_params< T1, T2 >::unit_type
{ }; -- Best regards, Andrey mailto:andysem@mail.ru