Reputation: 111
I'm trying to find a solution to have constant numeric literals inside template class method. I'm making some math template classes to be used with float or double types. The problem is that literals are different depending on data type (for example "0.5f" for float and "0.5" for double). So far, I come up with two solutions. Some hypothetical code for first one:
template <typename T>
class SomeClass
{
public:
T doSomething(T x);
};
template <>
float SomeClass<float>::doSomething(float x)
{
float y = 0.5f;
/*
* Do computations...
*/
return x;
}
template <>
double SomeClass<double>::doSomething(double x)
{
double y = 0.5;
/*
* Do computations...
*/
return x;
}
The approach above forces rewriting whole methods for every type it is used with.
Another approach:
template <typename T>
class SomeClass
{
public:
T doSomething(T x);
private:
T getValue();
};
template <typename T>
T SomeClass<T>::doSomething(T x)
{
T y = getValue();
/*
* Do computations...
*/
return x;
}
template <>
float SomeClass<float>::getValue()
{
return 0.5f;
}
template <>
double SomeClass<double>::getValue()
{
return 0.5;
}
This one doesn't require to write same methods multiple times for specific type, but requires to have a lot getValue() methods for every "magic number" that need to be used inside the method.
Is there another, "more elegant" way to solve this?
Upvotes: 10
Views: 6604
Reputation: 111
Thank you all for your answers and comments. I allowed myself to make a summary of what has been said so far and add my conclusions.
I'm going to implement some math class template to be instantiated to use with float or double type. There is a need to use some numeric literals internally in the class. They will be some commonly used numeric literals and constants, such as 0.0, 0.5, 1.0, pi, etc. I'm looking for a solution to make class instantiation work on different literals depending on its type.
Whether or not use float and double literals?
Talk went slightly on the topic whether or not bother to use separate literals for float and double. This might be caused by a bit unfortunate example I gave in my question. In the example literal will be converted to proper type at compile time anyway, so no harm done. But in general there will be cases where literal needs to be used in expression, for example:
float foo(float x)
{
return x * 3.14;
}
This will force compiler to convert x to double, make computations, then convert result back to float. Pros and cons of such behavior:
Pros:
Cons:
In conclusion, the goal is to make class instantiation work on proper types without any additional conversions. The idea to use double type literals everywhere, such as 0.5 and leave handling proper conversion to compiler is not an option.
More on the subject: Should we generally use float literals for floats instead of the simpler double literals?
Possible solutions?
getValue<type>()
methods, or as Jonathan Wakely
posted - specialized
members. This might lead to have some silly named members or methods
in the class, such as getZeroPointFive<float>()
.static_cast<T>()
will do the trick. Conversion to proper type will
be done at compile time.Upvotes: 1
Reputation: 106196
You just don't need to worry about this - use 0.5 and if the type is float the compiler will still initialise it optimally to the same value as if you'd used 0.5f.
It's a bit long-winded, but you might want to read through the "other mechanisms supporting polymorphism" part of my answer here: Polymorphism in c++
For more general usage of the float constant throughout the function - particularly in comparisons and expressions - it's worth reading the link bluemess mentions below....
Upvotes: 0
Reputation: 171383
Assuming it's actually necessary to use different values in the two specializations (it's not necessary for 0.5 and 0.5f, for example) it would be a lot less typing to do:
template <typename T>
class SomeClass
{
public:
T doSomething(T x);
private:
static const T magic_number_1;
};
template <typename T>
T SomeClass<T>::doSomething(T x)
{
T y = magic_number_1;
/*
* Do computations...
*/
return x;
}
template <>
const float SomeClass<float>::magic_number_1 = 0.5f;
template <>
const double SomeClass<double>::magic_number_1 = 0.5;
Upvotes: 1