Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does one increase precision in C++ templates in a template typename-dependent manner?

Tags:

c++

templates

stl

I have a templated math function which takes two values, does some math to them, and returns a value of the same type.

template <typename T>
T math_function(T a, T b) {
  LongT x = MATH_OP1(a,b);
  return MATH_OP2(x,a);
}

I want to store intermediate values (in x) in a type which is basically the long version of T (above, called LongT). So, if T is float, I want x to be a double; and if T is an int, I want x to be a long int.

Is there some way to accomplish this? I tried enable_if, but it seems that I would really need an enable_if_else.

I'd prefer to have the compiler figure out what to use for LongT on its own. I'd rather not have to specify it when I call the function.

like image 839
Translunar Avatar asked Dec 09 '22 22:12

Translunar


2 Answers

You can define a type mapping that will yield the needed type:

template <typename T> struct long_type;
template <> struct long_type<int> {
   typedef long type;
};
template <> struct long_type<float> {
   typedef double type;
};

And then use that metafunction:

template <typename T>
T math_function(T a, T b) {
  typename long_type<T>::type x = MATH_OP1(a,b);
  return static_cast<T>(MATH_OP2(x,a));
}

With this particular implementation, your template will fail to compile for any type other than the ones for which you have provided the long_type trait. You might want to provide a generic version that will just map to the itself, so that if the input is long long int that is what is used (assuming no larger type in your architecture).

like image 183
David Rodríguez - dribeas Avatar answered May 12 '23 15:05

David Rodríguez - dribeas


Assuming you don't need to handle T=long for example, just create traits for int and float:

template <typename T>
struct LongT;

template <>
struct LongT<int>
{
    typedef long value_type;
};

template <>
struct LongT<float>
{
    typedef double value_type;
};

template <typename T>
T math_function(T a, T b) {
  typename LongT<T>::value_type x = MATH_OP1(a,b);
  return MATH_OP2(x,a);
}
like image 22
Mark B Avatar answered May 12 '23 15:05

Mark B