整数和实数类型的不同模板行为

时间:2015-05-07 14:58:52

标签: c++ templates c++11

如何为不同类型(某些伪语言)创建具有不同行为的模板,例如:

template <typename T>
T GetRand(T param)
{
    if (T is of any real type) {
        // use uniform_real_distribution
    }

    if (T is of any integer type) {
        // use uniform_int_distribution
    }

    if (T is of any other type) {
        // do nothing
    }
}

如何撰写if T is of xxx type

如果有意义,我使用C ++ 11。

2 个答案:

答案 0 :(得分:5)

使用if语句的问题在于,无论是否实际运行该代码,都需要对任何T进行编译。

您最好使用专业化或类似的方式来指定您的行为。使用SFINAE和type_traits标题的示例:

template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
T GetRand(T param)
{
   cout << "int version\n"; 
}

template <typename T, std::enable_if_t<std::is_floating_point<T>::value>* = nullptr>
T GetRand(T param)
{
   cout << "float version\n"; 
}

template <typename T,
          std::enable_if_t<!(std::is_floating_point<T>::value ||
                             std::is_integral<T>::value)>* = nullptr>
T GetRand(T param)
{
   cout << "other version\n"; 
}

答案 1 :(得分:4)

您可以在GetRand的每次重载时使用SFINAE,但在某些时候使用tag-dispatch变得更加简单。我们将为每个潜在的重载选择一个唯一的类型(“T是任何实际类型”,“T是任何整数类型”,“其他”并构造正确的一个作为辅助函数的第二个参数。

首先,我们必须选择正确的标签:

struct integral_tag{};
struct floating_tag{};
struct other_tag{};

template <typename T>
struct get_tag 
: std::conditional<
    std::is_integral<T>::value,
    integral_tag,
    typename std::conditional<
        std::is_floating_point<T>::value,
        floating_tag,
        other_tag>::type
    > 
{ };

template <typename T>
using get_tag_t = typename get_tag<T>::type;

然后,我们使用该类型特征进行转发:

template <typename T>
T GetRand(T param) {
    return GetRand(param, get_tag_t<T>{} );
}

然后只写那些重载:

template <typename T>
T GetRand(T param, integral_tag ) { ... };

template <typename T>
T GetRand(T param, floating_tag ) { ... };

template <typename T>
T GetRand(T param, other_tag ) { ... };

就个人而言,我认为这更容易阅读。