如何使用 std::is_integral<> 选择实现?

How do I use std::is_integral<> to select an implementation?

本文关键字:实现 gt 选择 lt integral 何使用 std is      更新时间:2023-10-16

如果std::is_integral<>::value为真,我试图返回int64_t

否则,我想对对象调用to_int64t()

我下面的尝试失败了,因为函数模板的部分专门化是不允许的。

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

函数模板不能部分特化,一般来说,使用函数模板特化不是一个好主意。

实现您想要的一种方法是使用一种称为标记调度的技术,它基本上包括提供一个转发器函数,该函数根据额外的虚拟参数的值选择正确的过载:
#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 );
}

另一种可能性是使用基于std::enable_if的经典SFINAE技术。这就是它的样子(注意,从c++ 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 );
}

你可以直接使用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();
}