【笔记】enable_if 的使用
参见:
C++11 enable_if 的使用 - ouuan的博客
Effective C++ 42:typename 的两种用法 | Harttle Land
std::enable_if - cppreference.com
然后就可以写出这样的代码:
mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());
template<typename T, enable_if_t<is_integral<T>::value, bool> = 0>
T rd(T l, T r) { return uniform_int_distribution<T>(l, r)(rnd); }
template<typename T, enable_if_t<is_floating_point<T>::value, bool> = 0>
T rd(T l, T r) { return uniform_real_distribution<T>(l, r)(rnd); }
int main() {
cout << rd(1, 10); // sample output: 7
cout << rd(1.1, 3.3); // sample output: 1.25297
return 0;
}
理解起来还是有点复杂的。首先 enable_if_t
是 C++14 加入的一个语法糖:
template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type;
这里 =
号后面的 typename
用来声明 enable_if<B,T>::type
是一个类型而不是变量,因为在使用模板的情况下编译器无法得知 enable_if<B,T>::type
是类型还是变量。你可能会问在调用模板的时候当然是知道它是类型还是变量的啊,但根据这里的解释,编译器在通过实际的调用来生成代码之前有一个对模板的解析(这样才能生成候选列表之类的吧)。
然后是不能写成这样:
struct T {
enum { int_t,float_t } m_type;
template <typename Integer,
typename = std::enable_if_t<std::is_integral_v<Integer>>
>
T(Integer) : m_type(int_t) {}
template <typename Floating,
typename = std::enable_if_t<std::is_floating_point_v<Floating>>
>
T(Floating) : m_type(float_t) {} // 错误:不能重载
};
因为两个函数模板仅有缺省的参数不同,会被认为是同一个函数。
正确的写法利用模板的非类型参数,因为在函数模板等价规则里认为只有每个非类型的类型相同,两个函数模板才是等价的。