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

时间:2014-03-01 17:54:46

标签: c++ c++11 sfinae

我想根据给定的类型为std::uniform_*_distribution制作特征。 E.g:

distribution_traits<float>::type int_dist;

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

实施1

std::enable_iftypedef s:

一起使用
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>());
};

BTW,如果将dist函数放入distribution_traits,则编译将失败并出现错误:函数仅在返回类型方面不同,不能重载。 :(

1 个答案:

答案 0 :(得分:1)

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的第二个参数:

模板 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>;
};

否则您定义的专业化为distribution_traits<T, uniform_int_distribution<T>>且与distribution_traits<float>之类的实例化不匹配,因为第二个参数默认为void