简体   繁体   English

将enable_if与is_integral一起使用以制作分发特征

[英]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_iftypedef一起使用:

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.

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