关于可变参数模板函数与普通模板函数行为差异的技术问询
关于可变参数模板函数与普通模板函数行为差异的技术问询
咱们来看这么一个C++代码里的有意思现象:同样是模板函数,可变参数版本和普通模板版本在显式指定模板参数并传入基础类型值时,行为居然不一样,一起来拆解背后的原因。
首先看定义部分的代码:
template<class... T> struct Strct { Strct(double){}; }; template<class... T> void foo(Strct<T...>) {} template<class T> void foo2(Strct<T>) {}
再看调用代码:
foo<double>(1.); // error: no matching function for call to 'foo<double>(double)' foo2<double>(1.); // Ok
差异原因分析
对于
foo2<double>(1.):
我们显式指定了模板参数T=double,此时函数foo2的参数类型被确定为Strct<double>。编译器接下来只需要把传入的1.(double类型)通过Strct<double>的非显式构造函数隐式转换为Strct<double>对象,这个转换完全合法,所以调用成功。对于
foo<double>(1.):
这里的关键是可变参数模板的参数包特性:当我们显式指定foo<double>时,只是给参数包T...传入了第一个参数double,但参数包允许包含更多类型参数。因此编译器会尝试从传入的1.(double类型)推导参数包中剩余的模板参数,但double类型无法匹配Strct<T...>的参数类型,导致模板参数推导失败,最终编译器找不到匹配的函数,报出错误。
如果想让foo的调用也合法,有两种简单方式:
- 完全指定参数包,让编译器不需要推导:
foo<double>(Strct<double>{1.}); - 让编译器自动推导全部模板参数:
foo(1.);(此时T...会被推导为空参数包,因为Strct<>可以用double构造)
内容来源于stack exchange
相关产品推荐
相关产品推荐

