enable_if在函数模板中的一些用法

例子取的别人的,自己做下理解
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;
	};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值