
I was almost done implementing benchmark with fixed_int and voronoi library when next problem appeared. Let's consider following code snippet:
#include <iostream> #include "boost/multiprecision/fixed_int.hpp" using namespace boost::multiprecision;
template <typename T> void foo(const T& that) { std::cout << "Using default foo." << std::endl; }
template <> void foo<mp_int512_t>(const mp_int512_t& that) { std::cout << "Using fixed_int specialization." << std::endl; }
int main() { mp_int512_t a = 1; mp_int512_t b = 2; foo(a); // outputs 'Using fixed_int specialization.' foo(a * b); // outputs 'Using default foo.' return 0; }
I understand the reason of such behaviour (results of the expressions are stored as some intermediate objects), but in my implementation I need to specify template function specialization that converts fixed_int to double. Any suggestions on how to fix this?
Nod. It is a problem, and it's highlighted in the docs. BTW does your code work with mpz_class? If so it should be expression template safe already.... but leaving that aside, your options are: 1) Overload for the expression template type - but that's an implementation detail, and may result in a lot of unnecessary overloads. 2) Whenever you call a function template with an expression as argument, cast the result of the expression to the number type, so for example: foo(static_cast<number_type>(a+b)); The static_cast should be a no-op if the result of a+b is already that type, otherwise the expression template gets converted to it's actual number. 3) As above but provide the template argument explicitly: foo<number_type>(a+b); 4) For public API's it may be convenient to provide some traits classes and write: template <class A1, class A2, class A3> typename result_type<A1, A2, A3>::type foo(const A1& a1, const A2& a2, const A3& a3) { return foo_imp<typename calculation_type<A1, A2, A3>::type>(a1, a2, a3); } Then if the user calls foo(unsigned, long long, short); The arguments will get correctly promoted internally and return an appropriately sized result. The traits result_type and calculation_type might be the same type of course, and could probably just be wrappers around boost::common_type from type_traits (or maybe even *be* that type??). For what it's worth, Boost.Math does (2) for internal calls, and (4) for public API's, of course with floats you don't have to worry about the whole signed/unsigned business which may scupper (4) somewhat. Apologies for the long answer! HTH, John.