user2746401
user2746401

Reputation: 3436

Bit shift compile error from template instantiation with float type

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

Answers (3)

Elohim Meth
Elohim Meth

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

Jarod42
Jarod42

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

TartanLlama
TartanLlama

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

Related Questions