C++函数模板排序中空函数参数包的降优先级规则解析
你的推导偏差核心是漏了函数模板偏序规则中专门针对尾随参数包的补充判定条款,完整的判定逻辑如下:
前置流程
对调用f(&i),两个f模板都可以完成模板实参推导:
- #1 推导为
f<int*>,形参类型为(int*, ...),空包展开后签名为void f(int*) - #2 推导为
f<int*>,签名为void f(int*)
两个可行函数的参数转换优先级完全一致,常规重载决议无法区分,因此进入模板偏序判定流程。
常规双向推导
偏序的常规判定逻辑是:为每个模板构造一组无任何cv/引用属性的合成唯一类型实参,尝试用该组实参推导另一个模板的模板参数:
- 如果模板A的合成实参可以成功推导出模板B的实参,称B至少和A一样特化
- 如果仅存在单向的成功推导,推导目标方更特化
对#1和#2的常规双向推导确实均成功:
- 用#2的单合成实参(类型A)推导#1:第一个形参T推导为A,尾随参数包U...无对应后续实参,被推导为空包,推导成功,说明#1至少和#2一样特化
- 用#1的合成实参推导#2:#1的非包形参为第一个参数(合成类型A1),可成功推导#2的T为A1,后续尾随包U...不要求#2有对应形参,推导成功,说明#2至少和#1一样特化
尾随参数包的特殊判定
你之前的错误就出在这一步:双向推导均成功不代表直接判定互不更特化,偏序规则明确给出了尾随参数包场景的补充条款:
若双向常规推导均判定两个模板至少和对方一样特化,且其中模板G带有尾随函数参数包,另一模板F没有对应该参数包的形参,同时F自身没有尾随函数参数包,则F的特化度高于G。
对应f的两个重载完全满足该条款的适用条件:
- #1是带尾随参数包
U...的模板G - #2没有对应
U...的形参,自身也无尾随参数包,即模板F
因此#2的特化度高于#1,重载决议最终选择#2,不存在歧义。
为什么g(&i)选择#3
g的重载判定不需要走到上述尾随包补充条款,常规双向推导阶段就已经分出优先级:
- 用#4的单合成实参(普通类型A)推导#3:#3的第一个形参是
T*,普通类型A无法匹配指针类型的模板参数推导,该方向推导失败 - 用#3的合成实参(第一个参数为指针类型
A*,后续为包参数)推导#4:第一个形参T可成功推导为A*,后续包参数不要求#4有对应形参,该方向推导成功
因此常规推导阶段就判定#3特化度高于#4,最终选择#3。
内容的提问来源于stack exchange,提问作者user3188445
相关产品推荐
相关产品推荐

