C++重载函数模板偏序判定中P/A推导失败原因咨询
问题说明
C++参考文档中给出了如下函数模板偏序排序示例:
template<class T> void f(T, T*); // #1 template<class T> void f(T, int*); // #2 void m(int* p) { f(0, p); // 对#1推导结果: void f(T, T*) [T = int] // 对#2推导结果: void f(T, int*) [T = int] // 进入偏序排序流程: // 用#2作为实参模板推导#1: void(T,T*) 匹配 void(U1,int*): P1=T, A1=U1: T=U1 // P2=T*, A2=int*: T=int: 推导失败 // 用#1作为实参模板推导#2: void(T,int*) 匹配 void(U1,U2*): P1=T A1=U1: T=U1 // P2=int* A2=U2*: 推导失败 // 两个模板不存在更特化的版本,调用歧义 }
存在疑问:推导#1 from #2时,匹配P2=T*、A2=int*可得到T=int,看起来推导应该成功,但示例标注该步骤失败,不清楚失败原因。
失败原因
你的误区在于混淆了常规模板实参推导和偏序排序阶段的模板推导规则:偏序推导阶段完全不使用实际调用传入的实参类型,所有用于推导的实参,都是从作为对比基准的模板的模板参数生成的唯一虚构类型,和真实调用场景的类型无关。
具体到#1 from #2的推导流程:
- 该步骤的目标是验证:能否用#2的形参列表作为实参,推导出#1的模板参数。首先会给#2的所有模板参数分配全局唯一的虚构合成类型,这里#2只有一个模板参数,我们给它分配虚构类型
U1,展开后#2的形参列表为void(U1, int*),这就是本次推导使用的实参列表A。 - 用实参列表A匹配#1的形参列表P
void(T, T*),逐参数做模板推导:- 匹配第一个参数:P位置类型是
T,A位置类型是U1,推导得到T = U1 - 匹配第二个参数:P位置类型是
T*,A位置类型是int*,按指针匹配规则推导得到T = int
- 匹配第一个参数:P位置类型是
- 同一个模板参数
T被推导出两个完全不同的结果U1和int,推导出现冲突,因此整个推导过程直接失败。
对应的#2 from #1推导失败逻辑类似:
- 给#1的模板参数分配唯一虚构类型
U2,展开后#1的形参列表为void(U2, U2*),作为本次推导的实参列表A。 - 用A匹配#2的形参列表P
void(T, int*):- 第一个参数匹配得到
T = U2 - 第二个参数P位置是固定类型
int*,A位置是虚构类型指针U2*,U2是和int无关联的独立合成类型,无法匹配,推导失败。
- 第一个参数匹配得到
两个方向的偏序推导全部失败,因此两个模板没有谁更特化,最终调用触发歧义错误。
内容的提问来源于stack exchange,提问作者mkckr0
相关产品推荐
相关产品推荐

