c++ - 使用 enable_if 和 is_integral 来制作分布特征

标签 c++ c++11 sfinae

我想根据给定的类型为 std::uniform_*_distribution 创建一个特征。例如:

distribution_traits<float>::type int_dist;

我尝试了以下方法,但没有一种编译通过,我也不知道为什么。

实现 1

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 提示:

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.

实现 2

使用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>;
};

Clang 提示

dist_traits.cpp:28:3: error: implicit instantiation of undefined template 'distribution_traits<float, void>'
  distribution_traits<float>::type int_dist;
  ^

两种方式都无法被MSVC++ 12.0编译,报错信息也类似。

谁能解释一下我在 SFINAE 上做错了什么?谢谢!


对于那些对解决方案感到好奇的人,这里是编译的那个:

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>());
};

顺便说一句,如果将 dist 函数放入 distribution_traits 中,编译将失败并出现错误:函数仅在返回类型上不同,无法重载。 :(

最佳答案

SFINAE 可用于在替换模板参数期间丢弃函数模板和类模板特化的重载。

它不能像您尝试的那样与类型/模板别名一起使用。

关于您的工作代码 - 放置 dist类内部不起作用,因为您试图调用 dist里面decltype没有对象。制作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>());
};

要使实现 2 起作用,您需要省略 enable_if 的第二个参数:

模板 结构分布特征;

template <typename T>
struct distribution_traits<
    T, typename std::enable_if<std::is_integral<T>::value>::type> {
  using type = std::uniform_int_distribution<T>;
};

否则你定义的特化是distribution_traits<T, uniform_int_distribution<T>>这与 distribution_traits<float> 这样的实例不匹配因为第二个参数默认为void .

关于c++ - 使用 enable_if 和 is_integral 来制作分布特征,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22118050/

相关文章:

C++ 创建多个派生类的数组

c++ - 如何从 QProcess 获取 QWidget 并与之交互

c++ - 如何使用模板找到参数 T 的最大可解引用级别

c++ - 如何实现 'virtual ostream & print( ostream & out ) const;'

c++ - 在执行过程中替换可执行文件时如何处理 "/proc/self/exe"的 readlink()?

C++ 中的正则表达式转义

c++ - C++11 中的递归 lambda 函数

c++ - enable_if 函数在不应该定义的时候定义

c++ - 为什么 SFINAE 在这种情况下不起作用?

c++ - 模板中允许标量和 vector 类型