This is a really minimalist example. I'm using Boost.Units in the following way:
#define REAL double
...
using namespace boost::units;
quantity<si::velocity, REAL> v;
then sometimes I need to have something like
quantity<si::velocity, REAL> v_halved;
v_halved = 0.5 * v;
This works ok, because the compiler treats 0.5
as double
. But, when REAL
is something different then I get a compile error, e.g. if I changed the definition of REAL
to long double
the compile complains:
error: no match for ‘operator*’ in ‘5.0e-1 * v’
/usr/include/boost/units/detail/one.hpp:58: note: candidates are: boost::units::one boost::units::operator*(const boost::units::one&, const boost::units::one&)
Looking into the Boost.Units documentation I founded that the operator*
is overloaded as follows:
// runtime scalar times quantity
template<typename Unit, typename X>
multiply_typeof_helper< X, quantity< Unit, X > >::type
operator*(const X & lhs, const quantity< Unit, X > & rhs);
Although it is clear from the definition that the scalar and the internal type of the quantity must be the same, I would expect that the compiler automatically converts the type when the conversion can be done implicitly (like from double
to long double
). However I think that I might be missing something because the automatic type conversion certainly works for other simple functions like long double f(long double const & ld)
.
My problem is that I have used expressions like v_halved = 0.5 * v
quite a lot and my project has become considerably large already, and it is only now, after having to define REAL
as long double
that I realize this is a problem. So, I was wondering about a workaround/solution to this, I'm aware that static_cast<REAL>(0.5)
would be a solution, but I still feel that I'm missing something about the compiler not being able to automatically convert the scalar to the right type.
Thanks a lot in advance!
template functions are different that non template function. Compiler decide to select template function without considering the implicit casting/promotions. It just look for exact matching.
This is how C++ works in this area.
To get exact matching you would need such operator *
definition (notice this extra template param Y):
template<typename Unit, typename X, typename Y>
typename multiply_typeof_helper< X, quantity< Unit, X > >::type
inline operator*(const Y & lhs, const quantity< Unit, X > & rhs)
{
return static_cast<X>(lhs) * rhs;
}
but I am afraid that will interfere with boost definition of *
. You can play with this - like define your own quantity
which will derive almost entirely from boost - but define multiplication in different way, proposed by me.
Just decide what is easier for you to go with
L
- 0.5L
to make long double constant)