Jonathan Mee
Jonathan Mee

Reputation: 38939

std::numeric_limits as a Condition

Is there a way that I can use std::numeric_limits<T>::is_integer and std::numeric_limits<T>::is_specialized to change template behavior?

For example can I do this:

template < typename T >
void foo( const T& bar )
{
    if( std::numeric_limits< T >::is_integer )
    {
        isInt( bar );
    }
    else if( std::numeric_limits< T >::is_specialized )
    {
        isFloat( bar );
    }
    else
    {
        isString( bar );
    }
}

Upvotes: 2

Views: 1434

Answers (2)

Rapptz
Rapptz

Reputation: 21317

What you have is currently valid. However, you should prefer to use SFINAE and <type_traits> instead since it would dispatch to a different function based on the type rather than rely on a branch condition (which may or may not be optimized away).

You can use std::enable_if to do the following:

template<typename T, 
         typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void foo(const T& t) {
    isInt(t);
}

template<typename T, 
         typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
void foo(const T& t) {
    isFloat(t);
}

template<typename T, 
         typename std::enable_if<!std::is_integral<T>::value && 
                                 !std::is_floating_point<T>::value, int>::type = 0>
void foo(const T& t) {
    isString(t);
}

Live Demo

The reason that the second parameter for enable_if is set to int is to save us some typing. If the int is left out then we'd have to do typename = typename std::enable_if<std::is_integral<T>::value>::type instead of just setting it to 0 which would save us a couple of characters to type. They're equivalent for all intents and purposes.

Upvotes: 8

kestrel
kestrel

Reputation: 1344

The "obvious" answer is that you could use something like std::enable_if.

For example:

template<typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer, void>::type
    foo(const T &bar) { isInt(bar); }
template<typename T>
typename std::enable_if<std::numeric_limits<T>::is_specialized, void>::type
    foo(const T &bar) { isFloat(bar); }

The problem with this approach is that this is ambiguous for (as an example) an int parameter, since numeric_limits<int>::is_specialized == true.

To resolve this, I would simply use a better trait than numeric_limits, personally. You can also use boolean conditions to test for the exact condition you want:

template<typename T>
typename std::enable_if<std::numeric_limits<T>::is_specialized && !std::numeric_limits<T>::is_integer, void>::type
    foo(const T &bar) { isFloat(bar); }

Upvotes: 4

Related Questions