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()的结果true
// 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
}
上面的例子,通过编译器类型推倒机制,根据不同的条件生成不同的模板函数,实现灵活的函数重载。