【C++ Template | 06】std::enable_if和SFINAE

enable_if

SFINAE 是 substitution failure is not an error 的缩写,即匹配失败不是错误。就是说,匹配重载的函数 / 类时如果匹配后会引发编译错误,这个函数 / 类就不会作为候选。这是一个 C++11 的新特性,也是 enable_if 最核心的原理。

 头文件:

#include <type_traits>
template<bool B, class T = void>
struct enable_if;

这个模板实现相当简单,看一下一个版本的实现:

template<bool B, class T = void>
struct enable_if {};
 
template<class T>
struct enable_if<true, T> { typedef T type; };

 第一个普通版本的模板类定义,第二个为偏特化版本的模板类定义。它在第一个模板参数为false的时候并不会定义type,只有在第一模板参数为true的时候才会定义type。

1. 示例

 1 #include <iostream>
 2 #include <type_traits>
 3 using namespace std;
 4 
 5 template<int a, int b>
 6 typename enable_if <a + b == 233, bool>::type is233() {
 7     return true;
 8 }
 9 
10 template<int a, int b>
11 typename enable_if <a + b != 233, bool>::type is233() {
12     return false;
13 }
14 
15 int main() {
16     cout << is233<1, 232>() << endl;//true
17     cout << is233<114514, 1919>() << endl; //false
18     return 0;
19 }

2. 限制模板函数的参数类型

在某些场景下,我们需要实现只有特定类型可以调用的模板函数。如下代码所示,通过对返回值使用std::enable_if和在模板参数中使用std::enable_if均实现了只允许整形参数调用函数的功能。

 1 #include <iostream>
 2 #include <type_traits>
 3 
 4 template <class T>
 5 typename std::enable_if<std::is_integral<T>::value, bool>::type
 6 is_odd (T i) {
 7     return bool(i % 2);
 8 }
 9 
10 template < class T,
11            class = typename std::enable_if<std::is_integral<T>::value>::type>
12 bool is_even (T i) {
13     return !bool(i % 2);
14 }
15 
16 int main() {
17     short int i = 1;
18 
19     std::cout << std::boolalpha;
20     std::cout << "i is odd: " << is_odd(i) << std::endl;
21     std::cout << "i is even: " << is_even(i) << std::endl;
22 
23     return 0;
24 }

输出:

i is odd: true
i is even: false

3.模板类型偏特化

在使用模板编程时,可以利用std::enable_if的特性根据模板参数的不同特性进行不同的类型选择。如下所示,我们可以实现一个检测变量是否为智能指针的实现:

 1 #include <iostream>
 2 #include <type_traits>
 3 #include <memory>
 4 
 5 template <typename T>
 6 struct is_smart_pointer_helper : public std::false_type {};
 7 
 8 template <typename T>
 9 struct is_smart_pointer_helper<std::shared_ptr<T>> : public std::true_type {};
10 
11 template <typename T>
12 struct is_smart_pointer_helper<std::unique_ptr<T>> : public std::true_type {};
13 
14 template <typename T>
15 struct is_smart_pointer_helper<std::weak_ptr<T>> : public std::true_type {};
16 
17 template <typename T>
18 struct is_smart_pointer : public is_smart_pointer_helper<typename std::remove_cv<T>::type> {};
19 
20 template <typename T>
21 typename std::enable_if<is_smart_pointer<T>::value, void>::type check_smart_pointer(const T &t) {
22     std::cout << "is smart pointer" << std::endl;
23 }
24 
25 template <typename T>
26 typename std::enable_if < !is_smart_pointer<T>::value, void >::type check_smart_pointer(const T &t) {
27     std::cout << "not smart pointer" << std::endl;
28 }
29 
30 int main() {
31     int *p(new int(2));
32     std::shared_ptr<int> pp(new int(2));
33     std::unique_ptr<int> upp(new int(4));
34 
35     check_smart_pointer(p);
36     check_smart_pointer(pp);
37     check_smart_pointer(upp);
38 
39     return 0;
40 }
原文地址:https://www.cnblogs.com/sunbines/p/15260214.html