Reputation: 3436
I've got a templated function that operates on either floats or (unsigned) integer types like this:
template< typename T >
void typedFunc( T& data )
{
// .... lots of code ....
if( std::numeric_limits<T>::is_integer )
{
data = data << 8;
// .... do some processing ....
}
else
{
// .... do some slightly different processing ....
}
// .... lots more code ....
}
When I use the function for floating point types I get a compile error from the bit shift as you can't bit shift a float. For a float this bit of code never executes and (hopefully) is optimized away so just needs to compile. I can get rid of the compile error by casting data
to, say, an int but that changes the behaviour of the function when used with integer types.
How can I get this code to compile without changing its behaviour?
TIA
Upvotes: 3
Views: 144
Reputation: 1827
You should split your incompatible code using tag dispatch, like this:
template<typename T>
void doShift(T& data, std::false_type)
{ data = data << 8; }
template<typename T>
void doShift(T& data, std::true_type)
{ /* do something with float */ }
template< typename T >
void typedFunc( T& data )
{
// .... lots of code ....
doShift(data, typename std::is_floating_point<T>::type{});
// .... lots more code ....
}
Upvotes: 1
Reputation: 218108
You may split your method and specialize the non common part:
template< typename T >
void preTypedFunc( T& data )
{
// .... lots of code ....
}
template< typename T >
std::enable_if_t<std::numeric_limits<T>::is_integer>
midTypedFunc( T& data )
{
data = data << 8;
// .... do some processing ....
}
template< typename T >
std::enable_if_t<!std::numeric_limits<T>::is_integer>
midTypedFunc( T& data )
{
// .... do some slightly different processing ....
}
template< typename T >
void postTypedFunc( T& data )
{
// .... lots more code ....
}
template< typename T >
void typedFunc( T& data )
{
preTypedFunc(data);
midTypedFunc(data);
postTypedFunc(data);
}
Upvotes: 4
Reputation: 65730
The entire body of the template function needs to be valid for a given set of parameters, even if some of the code would never be executed for some type.
An easy way of getting around this is to separate your type-specific processing into a separate function and tag-dispatch to select from them:
template <typename T>
void doProcessing (std::true_type, T& data);
template <typename T>
void doProcessing (std::false_type, T& data);
//usage
doProcessing (std::is_integral<T>{}, data);
Upvotes: 1