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 }
  • 相关阅读:
    存储过程 游标 有用
    Spring框架IOC容器和AOP解析 非常 有用
    业务逻辑;完成根据自动分单结果来决定进行的相关业务处理
    业务逻辑:完成基于分区关键字匹配的自动分单业务逻辑
    业务逻辑:完成基于CRM地址完全匹配的自动分单业务逻辑
    业务逻辑:完成客户下单后前台系统的数据处理并调用后台系统服务处理业务 webservice接口调用 有用
    Spring IOC 少
    Spring IOC 巨多 非常 有用
    Spring ioc
    LeetCode -- Remove Element
  • 原文地址:https://www.cnblogs.com/sunbines/p/15260214.html
Copyright © 2011-2022 走看看