一般化的SFINAE规则
在C++模板中,有一条著名的规则,即SFINAE - Substitution failure is not an error,这个规则是对重载模板的参数进行展开时,如果类型不匹配,编译器也不会报错。这么说可能不直白,我们就用一个例子说明吧。
重载函数模板
在下面这个例子中,我们对模板函数f进行重载。第一个模板的参数为T::foo,第二个模板参数是一个T类型。然后分别使用Test类和int类型对模板f函数进行实例化,对于f<int>来说,并不存在int::foo类型,但编译器不会报错,而是继续寻找匹配的模板版本。
#include <iostream> using namespace std; class Test { public: typedef int foo; }; template <typename T> void f(typename T::foo){}// 第一个模板定义 template <typename T> void f(T){} // 第二个模板定义 int main() { f<Test>(10); f<int>(1); return 0; }
其实,通过这么一个简单的例子,我们就可以明白SFINAE规则的作用。一句话就是使得C++模板推导的规则符合程序员的预期结果,更加灵活。支持一些特殊的版本,还能使用通用的版本。
总结
在C++11标准对这样的状况,尤其是模板参数替换时使用了表达式的情况进行了明确规定,即表达式中没有出现“外部于表达式本身”的元素,比如说发生一些模板的实例化,或者隐式地产生一些拷贝构造函数的话,这样的模板推导都不会产生
SFINAE 失败(即编译器报错)。这样一来,C++11中的一些新特性将能够成功地进行广泛的应用,进一步地,新的STL也将因此受益。