【C++编程】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. 示例

#include <iostream>
#include <type_traits>
using namespace std;

template<int a, int b>
typename enable_if <a + b == 233, bool>::type is233() {
    return true;
}

template<int a, int b>
typename enable_if <a + b != 233, bool>::type is233() {
    return false;
}

int main() {
    cout << is233<1, 232>() << endl;//true
    cout << is233<114514, 1919>() << endl; //false
    return 0;
}

 

 

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

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

 

#include <iostream>
#include <type_traits>

template <class T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
is_odd (T i) {
    return bool(i % 2);
}

template < class T,
           class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even (T i) {
    return !bool(i % 2);
}

int main() {
    short int i = 1;

    std::cout << std::boolalpha;
    std::cout << "i is odd: " << is_odd(i) << std::endl;
    std::cout << "i is even: " << is_even(i) << std::endl;

    return 0;
}

 

输出:

i is odd: true
i is even: false

 

3.模板类型偏特化

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

#include <iostream>
#include <type_traits>
#include <memory>

template <typename T>
struct is_smart_pointer_helper : public std::false_type {};

template <typename T>
struct is_smart_pointer_helper<std::shared_ptr<T>> : public std::true_type {};

template <typename T>
struct is_smart_pointer_helper<std::unique_ptr<T>> : public std::true_type {};

template <typename T>
struct is_smart_pointer_helper<std::weak_ptr<T>> : public std::true_type {};

template <typename T>
struct is_smart_pointer : public is_smart_pointer_helper<typename std::remove_cv<T>::type> {};

template <typename T>
typename std::enable_if<is_smart_pointer<T>::value, void>::type check_smart_pointer(const T &t) {
    std::cout << "is smart pointer" << std::endl;
}

template <typename T>
typename std::enable_if < !is_smart_pointer<T>::value, void >::type check_smart_pointer(const T &t) {
    std::cout << "not smart pointer" << std::endl;
}

int main() {
    int *p(new int(2));
    std::shared_ptr<int> pp(new int(2));
    std::unique_ptr<int> upp(new int(4));

    check_smart_pointer(p);
    check_smart_pointer(pp);
    check_smart_pointer(upp);

    return 0;
}

 

posted @ 2021-09-12 21:37  苏格拉底的落泪  阅读(519)  评论(0编辑  收藏  举报