enable_if 是c++11标准引入的一个类模板,它的使用体现了c++编译器的SFINAE特性。对于没有使用过enable_if的同学来说,可能会显得有点突兀,下面先来一个例子。
template<typename T>
struct MEB
{
using type = T;
}
接着在main中如下使用:
MEB<int>::type abc = 15;
不难看到MEB::type 代表的就是int 类型。在理解了上面的例子后,接下来看看enable_if的实现源码,源码非常简单,如下:
template<bool _Test,class _Ty = void>
struct enable_if {};
template<class _Ty>
struct enable_if<true,_Ty>
{
using type = _Ty;
}
上述代码中定义了一个enbale_if类模板,其中_Test为非类型模板参数,_Ty为类型模板参数;接着实现了一个enable_if的偏特化版本,第一个参数设置为true.其实这个偏特化可以理解为一种条件分支语句,如enable_if类模板,当其第一个模板参数为true的时候,对应的分支就是偏特化版本的分支,反之就是泛化版本的分支。
在mian中添加如下代码:
std::enable_if< (3>2) >::type *myptr = nullptr;
编译一下,没有语法错误。因为该表达式的结果为true,走了偏特化的版本,第二个模板参数没有在程序中提供,就走了模板参数的默认值,void类型,所以上面的代码等价于:
void *myptr = nullptr;
但是如果改为如下的代码:
std::enable_if< (3<2) >::type *myptr = nullptr;
编译就如下提示:

这是由于走了泛化版本,这个版本中根本没有type这个类型别名。
ebable_if用于函数模板中:
有如下例子:
template<typename T>
typename std::enable_if<(sizeof(T) > 2) >::type funceb()
{
//...
}
现在在main中如下调用:
funceb<int>();
编译后发现没有错误,因为sizeof(int)>2.也就是将这个函数模板被实例化为:
void funceb()
{
//...
}
那如果如下调用,便会出错
funceb<char> ();
这是由于sizeof(char)<2,不满足条件,也没有找到其他合适的函数,所以会报错。
c++14标准对enable_if的用法做了简化,只需要在其后面增加一个_t,就可以省略typename和::type的输入,如下修改:
template<typename T>
typename std::enable_if_t<(sizeof(T) > 2) > funceb()
{
}
现在试想,如果给函数模板funceb()中的enable_if_t提供第二个模板参数,也就是
template<typename T>
std::enable_if_t<(sizeof(T) > 2), T > funceb()
{
}
那么当遇到funceb();会被实例化为:
int funceb()
{
//...
}
这显然需要一个返回值嘛,

于是修改为:
template<typename T>
std::enable_if_t<(sizeof(T) > 2), T > funceb()
{
T t = {};
return t;
}
int main()
{
int c = funceb<int>();
cout << c << endl;
system("pause");
return 0;
}
结果:
