zoukankan      html  css  js  c++  java
  • 【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 }
  • 相关阅读:
    Codeforces 1255B Fridge Lockers
    Codeforces 1255A Changing Volume
    Codeforces 1255A Changing Volume
    leetcode 112. 路径总和
    leetcode 129. 求根到叶子节点数字之和
    leetcode 404. 左叶子之和
    leetcode 104. 二叉树的最大深度
    leetcode 235. 二叉搜索树的最近公共祖先
    450. Delete Node in a BST
    树的c++实现--建立一棵树
  • 原文地址:https://www.cnblogs.com/sunbines/p/15260214.html
Copyright © 2011-2022 走看看