为何参数包前置时无法显式指定函数模板实参?
问题解析:可变模板参数位置对显式指定实参的影响
先看给出的代码:
template <typename T, typename ... Ts> void foo(T , Ts ... ) { } template <typename ... Ts, typename T> void bar(T , Ts ... ) { } int main() { foo<int, char>(1, 'c'); // 格式正确 foo(1, 'c'); // bar<int, char>(1, 'c'); // 格式错误 bar(1, 'c'); }
核心原因:参数包的"不确定性"导致匹配歧义
当你显式指定bar<int, char>(1, 'c')时,编译器根本搞不清你给的这两个实参怎么分配:
- 是把
int和char全分给前面的参数包Ts,那后面的T就没实参对应了? - 还是把
int分给Ts,char分给T?
因为参数包Ts是可变长度的,它可以包含0个、1个、多个类型,没有明确的"终止点"来划分哪些属于它、哪些属于后面的T。编译器没有办法确定你的意图,所以直接报错。
而foo的模板参数顺序是T在前、Ts在后,规则就很明确:显式指定的第一个实参对应T,剩下的所有实参都对应可变参数包Ts。比如foo<int, char>,int绑定T,char绑定Ts,没有歧义,所以能正常工作。
为什么隐式推导时两者都能正常运行?
隐式推导是基于函数参数的类型来反向推模板参数的:
- 对于
bar(1, 'c'),函数的第一个参数是int类型,对应模板里的T,剩下的char参数自然对应Ts,编译器能清晰对应每个模板参数的类型,不需要你显式指定,也就不存在歧义问题。 foo的推导逻辑类似,第一个参数的类型对应T,剩余参数对应Ts,同样清晰。
内容的提问来源于stack exchange,提问作者gonidelis
相关产品推荐
相关产品推荐

