Reputation: 3816
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.
Upvotes: 4
Views: 704
Reputation: 9144
template<typename T> struct LongT {typedef T type;}
template<> struct LongT<int8_t> {typedef int16_t type;}
template<> struct LongT<int16_t> {typedef int32_t type;}
template<> struct LongT<int32_t> {typedef int64_t type;}
template<> struct LongT<int64_t> {typedef intmax_t type;}
// same for unsigned ...
template<> struct LongT<float> {typedef double type;}
// template<> struct LongT<double> {typedef long double type;}
Used like so:
typename LongT<T>::type x;
Upvotes: 1
Reputation: 208406
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).
Upvotes: 5
Reputation: 21789
In C++11 you can use auto
keyword to retrieve type of the MATH_OP
. It is safe and handled by compiler.
auto x = MATH_OP1(a,b);
Upvotes: 3
Reputation: 55897
You can write your own specialisations of your own structure, or use something like
#include <type_traits>
template<typename T>
void func(const T& f, const T& s)
{
typename std::conditional
<
std::is_same<T, float>::value,
double,
typename std::conditional
<
std::is_same<T, int>::value,
long,
void
>::type
>::type X(f + s);
(void)X;
}
int main()
{
func(1, 1);
func(1.0f, 1.0f);
func(1.0, 1.0);
}
http://liveworkspace.org/code/8f75236b880a3fe210a8751e485a47ed
But write your own specializations as suggest David or Mark is pretty clever.
Upvotes: 0
Reputation: 96281
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);
}
Upvotes: 5