enable_if
enable_if (since c++11>)
enable_if
利用了模板匹配的技巧和struct
结构, 巧妙的将条件匹配分割成两种情况,
一种是true的情况: 为结构绑定一个type
一种是false的情况: 采取留空策略
template <bool _Test, class _Ty = void>
struct enable_if {}; // no member "type" when !_Test
// 这个实现叫做部分具体化(partial specialization), 即: 第一个参数 (<true>) 采用具体值.
// 这个模板函数简要但是浓缩了几个规则:
// 当调用时传递的参数是true时, 一定会进入这个函数.
// 当调用时传递的参数是true且不提供其他参数时, <class _Ty> 会把自动合并上面一个enable_if的 <class _Ty = void>;
// 当调用时传递的参数是true且提供其他参数时, _Ty 会替换成传递参数的类型(放弃void).
template <class _Ty>
struct enable_if<true, _Ty> { // type is _Ty for _Test
using type = _Ty;
};
enable_if_t (since c++14>)
它基于模板的 SFINAE 和 匿名类型参数 的基础概念上进行了简洁且完美的封装(落地).
enable_if_t
强制使用 enable_if
的 ::type
来触发 SFINAE
规则, 如果失败则跳过当前匹配进入下一个匹配.
template <bool _Test, class _Ty = void>
using enable_if_t = typename enable_if<_Test, _Ty>::type;
样例代码 (enable_if)
enable_if<is_integral<T>::value, int>
等同于 enable_if<true, int>
或者 enable_if<false, int>
,
如果第一个参数是 true , 那么 enable_if 这个结构就有一个 type 成员, 这时调用 enable_if::type 就是OK的.
如果第一个参数是 false, 那么 enable_if 这个结构就没有一个 type 成员, 这时调用 enable_if::type
就是失败的, 但是不会报错而是跳过当前匹配.
enable_if` 的第二个参数提供了一个`int`, 所以 `enable_if::type` 其实就是一个 `int`, 也就是说
`<typename T, typename enable_if<is_integral<T>::value, int>::type = 0>` 等同于
`<typename T, typename int = 0>` 等同于
`<typename T, int = 0>
#include <iostream>
using std::cout;
using std::endl;
template<typename T, typename enable_if<is_integral<T>::value, int>::type = 0>
void example(T t) {
cout << "template<typename T = book::author_type > void example();" << endl;
}
int main(void) {
example(10);
return 0;
}
样例代码 (enable_if_t)
enable_if_t
节省掉了 typename
和 ::type
, 是因为它背后使用 using
帮我们多谢了typename
和 ::type
(即: 强行重定义了类型).
#include <iostream>
using std::cout;
using std::endl;
// 省略了 typename
// 省略了 ::type
template<typename T, enable_if_t<is_integral<T>::value, int> = 0>
void example(T t) {
cout << "template<typename T = book::author_type > void example();" << endl;
}
int main(void) {
example(10);
return 0;
}
后面那个 = 0
是个什么东西?
由于 enable_if
第二个类型设定了默认为 void
类型,
typename enable_if::type
等同于 typename enable_if::void
, 本身不会报错,
由于 enable_if
或 enable_if_t
都是采取 匿名类型参数
形式来完成判断行为,
由于 匿名类型参数
必须要有一个默认值,
因此 typename enable_if::void = 0
是失败的, 它会导致程序跳过这个匹配.
因此 大部分的STL、TR1 的代码都会在使用 enable_if
或者 enable_if_t
时, 为第二个类型提供一个 int, 然后设定一个 0 为默认值.