如何为不同类型(某些伪语言)创建具有不同行为的模板,例如:
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。
答案 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 ) { ... };
就个人而言,我认为这更容易阅读。