C++ SFINAE

SFINAE的全称是: Substitution Failure Is Not An Error. 在进行模板匹配时, 可能会出现错误. 而当出现错误时, 不抛出错误, 而是继续去匹配别的模板. 这种情况就是SFINAE. 下面看一个例子:

#include <iostream>

// 仅仅是为了获取T的类型
template <bool B, typename T = void> struct enable_if {};
template <typename T> struct enable_if<true, T> { using type = T; };

// 判断是否有函数A()
template <typename T> struct has_func_A {
    // decltype返回最后一个表达式的结果, 即: bool()对象的类型
    // test的int参数是为了使用可变参数函数,因为模板函数的优先级大于可变参数函数
    template <typename C>
    static constexpr decltype(std::declval<C>().A(), bool()) test(int) {
        return true;
    }

    // black hole
    template <typename C> static constexpr bool test(...) { return false; }

    static constexpr bool value = test<T>(int());
};

// black hole
void O(...) { std::cout << "O" << std::endl; }

// 根据是否存在函数A, 来生成不同的重载函数
template <class T>
typename enable_if<has_func_A<T>::value, int>::type A(const T &obj) {
    return obj.A();
}

template <class T>
typename enable_if<!has_func_A<T>::value, void>::type A(const T &obj) {
    return O(obj);
}

class B {};

class C {
    public:
    int A() const {
        std::cout << "C" << std::endl;
        return 0;
    }
};

int main(void) {
    B b;
    C c;
    A<B>(b); // 输出: O
    A<C>(c); // 输出: C
}

上面的例子, 通过编译器类型推倒机制, 根据不同的条件生成不同的模板函数, 实现灵活的函数重载. 如果觉得有帮助,可以扫描右边的微信打赏码支持一下.

Leave a Reply

Your email address will not be published. Required fields are marked *