enable_if

转自 简书 极光火狐狸CPP

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_ifenable_if_t 都是采取 匿名类型参数 形式来完成判断行为,
由于 匿名类型参数 必须要有一个默认值,
因此 typename enable_if::void = 0 是失败的, 它会导致程序跳过这个匹配.
因此 大部分的STL、TR1 的代码都会在使用 enable_if 或者 enable_if_t 时, 为第二个类型提供一个 int, 然后设定一个 0 为默认值.

posted @ 2022-08-28 18:11  Cattle_Horse  阅读(471)  评论(0编辑  收藏  举报