简体   繁体   English

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

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

I'm trying to return an int64_t if std::is_integral<>::value is true. 如果std::is_integral<>::value为true,我正在尝试返回int64_t

Otherwise, I would like to call to_int64t() on the object. 否则,我想在对象上调用to_int64t()

My attempt below is failing because partial specialisation of function templates are not allowed. 我在下面的尝试失败,因为不允许部分特殊化功能模板。

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

Function templates cannot be partially specialized and, in general, it is not a good idea to use function template specialization. 函数模板不能部分专业化,一般来说,使用函数模板特化不是一个好主意。

One way to achieve what you want is to use a technique called tag dispatching , which basically consists in providing a forwarder function that selects the right overload based on the value of an extra dummy argument: 实现所需的一种方法是使用一种称为标签调度的技术,它基本上包括提供一个转发器函数,该函数根据额外伪参数的值选择正确的重载:

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

Another possibility is to use the classical SFINAE technique based on std::enable_if . 另一种可能性是使用基于std::enable_if的经典SFINAE技术。 This is how that could look like (notice that, since C++11, default template arguments on function templates are allowed): 这就是它的样子(注意,因为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 );
}

Yet another possibility, although more verbose, is to define helper class templates (which can be partially specialized) in a detail namespace and provide a global forwarder - I would not use this technique for this use case, but I am showing it because it might come handy in related design situations: 另一种可能性,虽然更详细,但是在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 );
}

You can just use std::enable_if : 你可以使用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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM