[英]Use enable_if with is_integral to make distribution traits
I want to make a traits for std::uniform_*_distribution
according to type given. 我想根据给定的类型为
std::uniform_*_distribution
做一个特征。 Eg: 例如:
distribution_traits<float>::type int_dist;
I tried following ways, but none of them compiles, and I don't know why. 我尝试按照以下方式进行操作,但是没有一种可以编译,也不知道为什么。
Implementation 1 实施1
Use std::enable_if
with typedef
s: 将
std::enable_if
与typedef
一起使用:
template <typename T>
struct distribution_traits {
using type = typename std::enable_if<std::is_integral<T>::value, std::uniform_int_distribution<T>>::type;
using type = typename std::enable_if<std::is_floating_point<T>::value, std::uniform_real_distribution<T>>::type;
};
Clang 3.4 complains: Clang 3.4抱怨:
dist_traits.cpp:7:9: error: redefinition of 'type'
using type = typename std::enable_if<std::is_floating_point<T>::value, std::uniform_real_distribution<T>>::type;
^
dist_traits.cpp:6:9: note: previous definition is here
using type = typename std::enable_if<std::is_integral<T>::value, std::uniform_int_distribution<T>>::type;
^
dist_traits.cpp:6:40: error: no type named 'type' in 'std::enable_if<false, std::uniform_int_distribution<float> >'; 'enable_if' cannot be used to
disable this declaration
using type = typename std::enable_if<std::is_integral<T>::value, std::uniform_int_distribution<T>>::type;
^~~~~~~~~~~~~~~~~~~~~~~~~~
dist_traits.cpp:28:3: note: in instantiation of template class 'distribution_traits<float>' requested here
distribution_traits<float>::type int_dist;
^
2 errors generated.
Implementation 2 实施2
Use enable_if
as class template parameter: 使用
enable_if
作为类模板参数:
template <typename T, typename distribution_t = void>
struct distribution_traits;
template <typename T>
struct distribution_traits<
T, typename std::enable_if<std::is_integral<T>::value,
std::uniform_int_distribution<T> >::type > {
using type = std::uniform_int_distribution<T>;
};
template <typename T>
struct distribution_traits<
T, typename std::enable_if<std::is_floating_point<T>::value,
std::uniform_real_distribution<T> >::type > {
using type = std::uniform_real_distribution<T>;
};
And Clang complains 和C抱怨
dist_traits.cpp:28:3: error: implicit instantiation of undefined template 'distribution_traits<float, void>'
distribution_traits<float>::type int_dist;
^
Either way cannot be compiled by MSVC++ 12.0, and the error messages are similar. 两种方法都不能通过MSVC ++ 12.0进行编译,并且错误消息类似。
Could anyone please explain what's wrong I'm doing with SFINAE? 谁能解释我对SFINAE的问题是什么? Thanks!
谢谢!
For those who are curious about solution, here is the one that compiles: 对于那些对解决方案感到好奇的人,这里有一份汇编:
template <typename T>
auto dist() -> typename std::enable_if<std::is_integral<T>::value, std::uniform_int_distribution<T>>::type;
template <typename T>
auto dist() -> typename std::enable_if<std::is_floating_point<T>::value, std::uniform_real_distribution<T>>::type;
template <typename T>
struct distribution_traits {
using type = decltype(dist<T>());
};
BTW, if put dist
function into distribution_traits
, the compilation will fail with error: function only differs in return type cannot be overloaded. 顺便说一句,如果将
dist
函数放入distribution_traits
,编译将失败并显示错误:函数仅在返回类型上有所不同,无法重载。 :( :(
SFINAE can be used to discard overloads of function templates and class template specializations during substitution of template arguments. SFINAE可用于在替换模板参数期间丢弃函数模板和类模板专门化的重载。
It cannot be used with type/template aliases like you're trying to do. 不能像您尝试的那样将其与类型/模板别名一起使用。
About your working code - putting dist
inside the class doesn't work because you attempt to call dist
inside decltype
without an object. 关于您的工作代码-将
dist
放入类中不起作用,因为您尝试在没有对象的情况下在decltype
调用dist
。 Make dist
static and it'll work: 使
dist
静态,它将起作用:
template <typename T>
struct distribution_traits {
template <typename U>
static auto dist() -> typename std::enable_if<std::is_integral<U>::value, std::uniform_int_distribution<U>>::type;
template <typename U>
static auto dist() -> typename std::enable_if<std::is_floating_point<U>::value, std::uniform_real_distribution<U>>::type;
using type = decltype(dist<T>());
};
For implementation 2 to work, you need to omit the second argument of enable_if
: 为了使实施2正常工作,您需要省略
enable_if
的第二个参数:
template struct distribution_traits; 模板struct distribution_traits;
template <typename T>
struct distribution_traits<
T, typename std::enable_if<std::is_integral<T>::value>::type> {
using type = std::uniform_int_distribution<T>;
};
otherwise the specialization you define is distribution_traits<T, uniform_int_distribution<T>>
and that doesn't match an instantiation like distribution_traits<float>
because the second parameter is defaulted to void
. 否则,您定义的专业化是
distribution_traits<T, uniform_int_distribution<T>>
,并且与像distribution_traits<float>
这样的实例化不匹配,因为第二个参数默认为void
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.