Std:: numeric_limits как условие

Есть ли способ, которым я могу использовать std::numeric_limits<T>::is_integer и std::numeric_limits<T>::is_specialized для изменения поведения шаблона?

Например, могу ли я сделать это:

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 );
    }
}

Ответ 1

"Очевидный" ответ заключается в том, что вы можете использовать что-то вроде std::enable_if.

Например:

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); }

Проблема с этим подходом заключается в том, что это (в качестве примера) неоднозначно для параметра int, поскольку numeric_limits<int>::is_specialized == true.

Чтобы решить эту проблему, я просто использовал бы лучшую черту, чем numeric_limits, лично. Вы также можете использовать логические условия для проверки того, какое именно условие вы хотите:

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); }

Ответ 2

То, что у вас есть, в настоящее время действует. Тем не менее, вы должны предпочесть использовать SFINAE и <type_traits>, так как он будет отправлять другую функцию, основанную на типе, а не полагаться на условие ветки (которое может или не может быть оптимизирован).

Вы можете использовать std::enable_if, чтобы сделать следующее:

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);
}

Живая демонстрация

Причиной того, что второй параметр для enable_if установлен на int, является сохранение некоторого ввода. Если int не указано, нам нужно сделать typename = typename std::enable_if<std::is_integral<T>::value>::type вместо того, чтобы просто установить его на 0, который сохранит нам пару символов для ввода. Они эквивалентны для всех целей и целей.