Подтвердить что ты не робот

Как использовать std:: is_integral <> для выбора реализации?

Я пытаюсь вернуть int64_t, если std::is_integral<>::value истинно.

В противном случае я хотел бы называть to_int64t() для объекта.

Моя попытка ниже не работает, поскольку частичная специализация шаблонов функций не разрешена.

CODE

#include <type_traits>
#include <cstdint>

template<class T,bool is_integral_type>
int64_t to_int64t( const T& t )
{
        return t;
}

template<class T>
int64_t to_int64t<T,std::is_integral<T>::value>( const T& t )
{
        return t;
}

template<class T>
int64_t to_int64t<T,!std::is_integral<T>::value>( const T& t )
{
        return t.to_int64t();
}

int main()
{
        int64_t i = 64;
        auto x = to_int64t( i );
}
4b9b3361

Ответ 1

Шаблоны функций не могут быть частично специализированными и, в общем, не рекомендуется использовать специализированную функцию.

Один из способов добиться того, что вы хотите, - использовать технику, называемую диспетчеризацией тегов, которая в основном состоит в предоставлении функции пересылки, которая выбирает правильную перегрузку на основе значения дополнительного аргумента фиктивного типа:

#include <type_traits>
#include <cstdint>

template<class T>
int64_t to_int64t( const T& t, std::true_type )
{
    return t;
}

template<class T>
int64_t to_int64t( const T& t, std::false_type )
{
    return t.to_int64t();
}

template<class T>
int64_t to_int64t( const T& t )
{
    return to_int64t(t, std::is_integral<T>());
}

int main()
{
    int64_t i = 64;
    auto x = to_int64t( i );
}

Другая возможность - использовать классический метод SFINAE на основе std::enable_if. Вот как это могло бы выглядеть (обратите внимание, что, поскольку С++ 11 допускаются аргументы шаблона по умолчанию для шаблонов функций):

#include <type_traits>
#include <cstdint>

template<class T, typename std::enable_if<
    std::is_integral<T>::value>::type* = nullptr>
int64_t to_int64t( const T& t )
{
    return t;
}

template<class T, typename std::enable_if<
    !std::is_integral<T>::value>::type* = nullptr>
int64_t to_int64t( const T& t )
{
    return t.to_int64t();
}

int main()
{
    int64_t i = 64;
    auto x = to_int64t( i );
}

Еще одна возможность, хотя и более подробная, состоит в том, чтобы определить шаблоны вспомогательных классов (которые могут быть частично специализированы) в пространстве имен detail и предоставить глобальный форвардер - я бы не использовал этот метод для этого варианта использования, но я показывая это, потому что это может пригодиться в связанных проектных ситуациях:

#include <type_traits>
#include <cstdint>

namespace detail
{
    template<class T, bool = std::is_integral<T>::value>
    struct helper { };

    template<class T>
    struct helper<T, true>
    {
        static int64_t to_int64t( const T& t )
        {
            return t;
        }
    };

    template<class T>
    struct helper<T, false>
    {
        static int64_t to_int64t( const T& t )
        {
            return t.to_int64t();
        }
    };
}

template<class T>
int64_t to_int64t( const T& t )
{
    return detail::helper<T>::to_int64t(t);
}

int main()
{
    int64_t i = 64;
    auto x = to_int64t( i );
}

Ответ 2

Вы можете просто использовать std::enable_if:

template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
int64_t to_int64t( const T& t )
{
        return t;
}

template<class T, typename std::enable_if<!std::is_integral<T>::value, int>::type = 0>
int64_t to_int64t( const T& t )
{
        return t.to_int64t();
}