You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的推导流程:

  1. 该步骤的目标是验证:能否用#2的形参列表作为实参,推导出#1的模板参数。首先会给#2的所有模板参数分配全局唯一的虚构合成类型,这里#2只有一个模板参数,我们给它分配虚构类型U1,展开后#2的形参列表为void(U1, int*),这就是本次推导使用的实参列表A。
  2. 用实参列表A匹配#1的形参列表Pvoid(T, T*),逐参数做模板推导:
    • 匹配第一个参数:P位置类型是T,A位置类型是U1,推导得到T = U1
    • 匹配第二个参数:P位置类型是T*,A位置类型是int*,按指针匹配规则推导得到T = int
  3. 同一个模板参数T被推导出两个完全不同的结果U1和int,推导出现冲突,因此整个推导过程直接失败。

对应的#2 from #1推导失败逻辑类似:

  1. 给#1的模板参数分配唯一虚构类型U2,展开后#1的形参列表为void(U2, U2*),作为本次推导的实参列表A。
  2. 用A匹配#2的形参列表Pvoid(T, int*):
    • 第一个参数匹配得到T = U2
    • 第二个参数P位置是固定类型int*,A位置是虚构类型指针U2*,U2是和int无关联的独立合成类型,无法匹配,推导失败。

两个方向的偏序推导全部失败,因此两个模板没有谁更特化,最终调用触发歧义错误。

内容的提问来源于stack exchange,提问作者mkckr0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 23:27:31