首先推荐讲SFINAE我认为最好的两个资料,一个是cppreferenceSFINAE,一个是channel9上Stephan T Lavavej讲的三个series:Core CPP,STL, Advacned STL其中的某一集。。。的确忘了是哪集了。这两个资料有深入有浅出,最重要的是讲明白了SFINAE的本质,而不是上来就一段代码告诉你这个就是SFINAE,看完了就看完了而已,完全和其他知识联系不起来。。。
推荐完资料,下面试着用最简单的方式来说清楚SFINAE。
SFINAE全名是"Substitution Failure Is Not An Error"。具体应用于构建function overload resolution set时候的template specialization。由于重载的存在,当编译期决定函数调用的时候,其实是先构建了一个重载函数候选的集合,然后在根据标准里的规则选出最佳的调用函数。如果存在function template,在构建这个集合的时候,编译器就开始进行模板特化。模板特化也就不可避免的涉及到类型操作。如果模板参数里面的某个类型替换失败,则这个模板特化失败,继续向下进行,而不是引起编译错误,这就是“替换失败并非错误”的本意了。
从这个解释可以看出,如果我们有意的控制模板特化时候的失败,就可以控制哪些特化可以进入重载候选集合,哪些特化直接被忽略掉,从而控制overload resolution的结果,成为编译期语言C++的一大利器。。。
最基本的差不多解释清除了,下面看代码。先是最简单的enable_if:
template<bool, typename _Tp = void>
struct enable_if
{ };
// Partial specialization for true.
template<typename _Tp>
struct enable_if<true, _Tp>
{ typedef _Tp type; };
可以看到,只有bool为true的时候,enable_if才会存在一个enable_if::type类型。
来自于cppreference的例子:
template<class T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
foo1(T t)
{
std::cout << "foo1: float\n";
return t;
}
如果T不是float,double什么的,这个模板函数可以直接当作不存在。
在enable_if的源码下面,还有:
template<typename... _Cond>
using _Require = typename enable_if<__and_<_Cond...>::value>::type;
利用enable_if和varadic template来对多个条件进行判断。
有空在补一点复杂些的代码。