分发好模板功能的最佳方式

时间:2016-05-13 07:32:28

标签: c++ templates c++11

我有三个功能几乎完全相同,但根据参数类型,过程有点不同:

template<typename T> void Func1(const T *in, T *out)
{
    static_assert(std::is_same<T, INT8>::value
                  || std::is_same<T, UINT8>::value
                  || std::is_same<T, INT16>::value
                  || std::is_same<T, UINT16>::value, "");
    //...
}

template<typename T> void Func2(const T *in, T *out)
{
    static_assert(std::is_same<T, INT32>::value || std::is_same<T, UINT32>::value, "");
    //...
}

template<typename T> void Func3(const T *in, T *out)
{
    static_assert(std::is_same<T, float>::value || std::is_same<T, double>::value, "");
    //...
}

但我不希望用户必须决定调用哪个函数,所以我尝试自动完成。不幸的是到目前为止(我是C ++初学者),我知道的唯一方法是:

template<typename T> void Function(const T *in, T *out)
{
    if (std::is_same<T, UINT8>::value
        || std::is_same<T, UINT16>::value
        || std::is_same<T, INT8>::value
        || std::is_same<T, INT16>::value)
    {
        Func1(in, out);
        return ;
    }

    if ( std::is_same<T,INT32>::value || std::is_same<T,UINT32>::value )
    {
        Func2(in, out);
        return ;
    }

    if ( std::is_same<T,float>::value || std::is_same<T,float>:: double )
    {
        Func3(in, out);
        return ;
    }
}

我发现这个解决方案非常难看,我想知道是否可以提供更好/更快/更优雅的东西?

2 个答案:

答案 0 :(得分:5)

如果您使用的是C ++ 11或更高版本,则可以使用type_traits(SFINAE):

template<typename T>
typename std::enable_if<std::is_same<T, INT8>::value 
            || std::is_same<T, UINT8>::value 
            || std::is_same<T, INT16>::value 
            || std::is_same<T, UINT16>::value>::type Function(const T*in, T*out)
{
    Func1(in, out);
}

template<typename T>
typename std::enable_if<std::is_same<T, INT32>::value 
            || std::is_same<T, UINT32>::value >::type Function(const T*in, T*out)
{
    Func2(in, out);
}

template<typename T>
typename std::enable_if<std::is_same<T, float>::value 
            || std::is_same<T, double>::value >::type Function(const T*in, T*out)
{
    Func3(in, out);
}

示例:http://coliru.stacked-crooked.com/a/b4f000fa6ffa8f19

或者,如果您不能使用C ++ 11或更高版本,则可以使用重载而不是模板:

void Function(const UINT8 *int, UINT8 * out)
{
    Func1(in, out);
} 
...
void Function(const UINT32 *int, UINT32 * out)
{
    Func2(in, out);
} 
...

或者你可以使用template specialization但是,在这种情况下,它并不是真正相关的(我把它留在这里,因为它是原始答案):

template<typename T> Function(const T *in, T *out);

template<> void Function(const UINT8 *in, UINT8 * out)
{
    Func1(in, out);
}

template<> void Function(const INT8 *in, INT8 * out)
{
    Func1(in, out);
}

....

答案 1 :(得分:4)

您可以编写特征来检查列表中是否显示类型。此版本使用C ++ 17中的std::disjunction,但您只需从链接中复制粘贴实现即可。

template <typename F, typename... T>
using is_one_of = std::disjunction<std::is_same<F, T>...>;

然后使用SFINAEstd::enable_if一起选择重载(std::enable_if_t是C ++ 14,如果您遇到11,请使用typename std::enable_if<...>::type。< / p>

template<typename T> 
std::enable_if_t<is_one_of<T, uint8_t, int8_t, uint16_t, int16_t>::value>
Func(const T *in, T *out)
{
    std::cout << "1\n";
}

template<typename T> 
std::enable_if_t<is_one_of<T, uint32_t, int32_t>::value>
Func(const T *in, T *out)
{
    std::cout << "2\n";
}

template<typename T> 
std::enable_if_t<std::is_floating_point<T>::value> 
Func(const T *in, T *out)
{
    std::cout << "3\n";
}

请注意,您甚至不需要Func1Func2Func3,您可以让不同的Func重载进行处理。

Live Demo