I'm managing units conversion. Say us that I reached a state where I achieve that.
The heart of my conversion between different units lies on the following generic template function:
template <class SrcUnit, class TgtUnit> extern
double convert(double val);
The goal of this function is to convert a physical magnitude expressed in units of type SrcUnit
to another expressed in units of type TgtUnit
.
I have a class called Quantity<Unit>
which manages the values and their unities and this class tries to give type safety and automatic conversion. By example, I export the following constructor:
template <class SrcUnit>
Quantity(const Quantity<SrcUnit> & q)
: unit(UnitName::get_instance())
{
check_physical_units(q); // verify that the physical magnitudes are the same
value = convert<SrcUnit, UnitName>(q.value); // <<- here the conversion is done
check_value(); // check if the value is between the allowed interval
}
I export other stuff where the conversion is done.
So, when someone wishes to manage a new unit, she specifies a new Unit
derived class. I achieve that by putting inside a macro all the needed specification of the new class. Now, it is the responsibility of this user to write the conversions functions. That is to write two specializations of the convert()
template. By example, suppose that you have a unit called 'Kilometerand you wish to specify a new unit called
Mile`. In this case, you do this:
Declare_Unit(Mile, "mi", "English unit of length", Distance,
0, numeric_limits<double>::max()); // macro instantiating a new Unit class
template <> double convert<Kilometer, Mile>(double val) { return val/1609.344; }
template <> double convert<Mile, Kilometer>(double val) { return 1609.344*val; }
Now, what happen if the user forgets to write a conversion function? Well, in this case the linker will fail because it cannot find the convert()
specialization.
Now my question.
Although I think a linker error is acceptable as behavior for reporting to the user the missing convert()
, I would like to test i compiling time for the existence of convert()
specialization. So my question is how could I achieve that? I guess through a static_assert
put just before each call to convert()
which tests if the specialization is already known. But how to do that?
PS: Also, it would be very useful for me if someone could recommend me a good text about C++ metaprogramming.
N^2
conversion functions? You have to implement bothKilometer
toMile
andMile
toKilometer
separately? – OceaniaN^2
conversion, then yes @Barry. And for the second question yes too. Note that there are cases where the conversion is not strictly linear; although this could sound bizarre, this is the case for some geological correlations where a conversion could be valid only inside an empirically valid interval. Inclusive, there are situations in which the conversion is only allowed in once sense. Anyway, any suggestion bout design is very welcome – CattleN^2
is that if you haveN
units, then each unit needs its own conversion function to every other unit... so you haveN^2
different conversion functions. That... doesn't scale very well. – Oceania