重载解析分三步:可行函数→候选函数→最佳匹配;先收集同名函数,再筛选参数可匹配的候选者,最后依转换序列质量选最佳,优先级为精确匹配>标准转换>用户定义转换>省略号,模板按实例化精度与非模板函数竞争。

重载解析分三步:可行函数 → 候选函数 → 最佳匹配
编译器不是“猜”哪个函数该调,而是严格走三阶段筛选:重载解析先收集所有同名函数(包括模板实例化后的版本),再过滤出参数个数、类型能“接住”实参的(即候选函数),最后在这些候选里挑一个最佳匹配。关键在于第三步——它不看函数体,只看调用点实参到形参的转换序列质量。
最佳匹配靠转换序列“距离”决定,不是“能不能转”而是“转得多不多”
比如 int 调用 void f(double) 和 void f(long long),两者都需用户定义转换或标准转换,但编译器会比较每一步转换的“层级”:int → double 是标准转换(提升),int → long long 也是标准转换(整型提升),此时两者“距离”相等,就报错ambiguous overload。常见陷阱是以为“能编译过去就行”,其实只要存在两个同样“近”的路径,就直接失败。
以下情况按优先级降序排列(越靠前越优):
-
精确匹配:类型完全一致,或仅涉及左值/右值引用限定符变化 -
左值转右值、数组转指针、函数转函数指针等无损转换 -
标准转换:如int → double、Derived* → Base* -
用户定义转换:通过operator T()或单参构造函数 -
省略号形参(...):永远垫底,只在没别的可选时才考虑
模板函数参与重载时,实例化发生在候选阶段,且转换规则不同
写 template<typename t> void f(T)</typename> 和 void f(int),传 int 时,f(int) 是精确匹配,f<int>()</int> 是模板实例化后也精确匹配——这时编译器按“非模板优于模板”裁决,选普通函数。但若传 short,f(int) 需标准转换,f<short>()</short> 是精确匹配,模板反而赢了。容易踩的坑是误以为“模板更泛化就更弱”,其实它在匹配精度上可以反超。
立即学习“C++免费学习笔记(深入)”;
注意:template<typename t> void f(T&)</typename> 和 void f(const int&) 对 int 实参来说,前者是精确匹配(int& 绑定 int),后者要加 const(标准转换),所以模板胜出——哪怕你本意是想用 const 版本。
隐式转换序列不能跨形参累积,“整体最优”不存在
重载解析对每个形参单独计算转换序列,然后整体判断是否“有一个函数在所有位置都不差、且至少一处更优”。它不会把第一个参数转得少、第二个参数转得多,再取个平均分。比如:
void g(int, double); void g(double, int);
调用 g(1, 1) 时,两个候选都是:一个参数精确匹配、另一个需标准转换。没有谁“更优”,直接报错ambiguous overload。这时候必须显式强制转换,比如 g(1, 1.0) 或 g(static_cast<double>(1), 1)</double>。
真正难缠的是自定义类型 + 多个用户转换函数 + 模板,此时编译器报的错误信息往往只说“candidate template ignored”,实际原因可能是某个隐式转换被禁用(比如 explicit 构造函数)、或 SFINAE 删掉了某个实例——这些不在转换序列比较范围内,而是在候选生成阶段就被筛掉了。









