例子取的别人的,自己做下理解
1、做返回值,并且可以提供约束
template<class T>
typename std::enable_if<std::is_integral<T>::value>::type
printIntegral(T t) {
std::cout << t;
}
如果传入的参数类型是int,比如printIntegral(1),那么这个函数的返回值就是void
如果传入double类型,比如printIntegral(1.0),编译器会推导失败,给出不type的类型。会给出提示:
如果想返回int类型的值呢,可以这样:
template<class T>
typename std::enable_if<std::is_integral<T>::value,int>::type
printIntegral(T t) {
std::cout << t;
return 0;
}
int main() {
printIntegral(1);
}
2、也可以放在参数里,辅助编译进行判断。这里面就有些知识点了:
template<class T>
void printIntegral(T t,
typename std::enable_if<std::is_integral<T>::value>::type* = 0) {
std::cout << t;
}
注意,这个函数的返回值类型,是直接给的,就是void
第二个参数,用来编译时的推导,但如果把后面的“=0”给去掉,就会编译失败:
另外,这里有个地方需要注意:函数的参数,即使给了默认参数,但不给变量名称,也是可以编译通过的,比如。
void printIntegral(int t, int =0)
{
std::cout << t;
}
int main() {
printIntegral(1);
}
3、把参数直接放在模板列表里,对哪些类型的参数可以使用这个函数进行限定:
template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void printIntegral(T t) {
std::cout << t;
}
int main() {
printIntegral(1);
}
注意后面的那个“=0”,如果去掉的话,就会出编译错误:
按理说,std::enable_if<std::is_integral<int>::value, int>::type的结果是得到一个类型,应该就是第二个int。这应该是一个“非类型参数”。
替换下来之后试试呢,也是同样的编译错误:
template<class T, int>
void printIntegral(T t) {
std::cout << t;
}
int main() {
printIntegral(1);
}
即使在调用时指定第二个参数也不行:
看来对于函数模板,不能用这种“非类型形参”。除非这样:
template<typename T, int=0>
void printIntegral(T t) {
std::cout << t;
}
int main() {
printIntegral(1);
}
只要不赋给默认值,都会编译失败:
有意思的事来了:
先看看这个,是可以通过编译的,没啥毛病,第二个参数是给了一个默认的int类型,在代码里面并没有用到R这个类型:
template<class T, typename R = int>
//或者template<class T, typename = int>
void printIntegral(T t) {
std::cout << t;
}
int main() {
printIntegral(1);
}
注意第二行,typename后面没有名字,也是可以的,毕竟代码里没用到第二个参数。
那么,下面的代码就可以编译成功了:
跟上面的代码的第二行是同样的意思了。而且编译器会带有推导过程:编译器把推导出来的int类型赋给一个“匿名”的参数类型“R”,这样就很合理了。
template<class T, typename =std::enable_if<std::is_integral<T>::value, int>::type>
void printIntegral(T t) {
std::cout << t;
}
int main() {
printIntegral(1);
}
而且确实是有推导过程的,如果用printIntegral(1.0)进行调用的话,会有编译错误,说明确实是推导了的:
注意,不能去掉后面的type,如果改成下面这样,不管是printIntegral(1)还是printIntegral(1.0) 都会编译成功。毕竟编译不成功,靠的就是enable_if匹配到泛化版本时,里面没有定义type
template<class T, typename =std::enable_if<std::is_integral<T>::value, int>>
void printIntegral(T t) {
std::cout << t;
}
int main() {
printIntegral(1);
}
另外,注意下面的代码
不管是:std::enable_if<std::is_integral<T>::value,int>::type
还是:std::enable_if<std::is_integral<T>::value>::type,
如果std::is_integral<T>推导出结果是false,
最后实例化的都是enable_if的泛化版本,而不是其偏特化版本:
// STRUCT TEMPLATE enable_if
template<bool _Test,
class _Ty = void>
struct enable_if
{ // type is undefined for assumed !_Test
};
template<class _Ty>
struct enable_if<true, _Ty>
{ // type is _Ty for _Test
using type = _Ty;
};