重载解析(overload resolution)是 C++ 编译器在调用重载函数时,根据实参在编译期选择最合适函数的过程。理解它的关键是掌握三个步骤和转换序列的等级。
1. 重载解析的三个步骤
假设有这样一次调用 f(args…),编译器按顺序执行:
第一步:确定候选函数(candidate functions)
候选函数是名字查找找到的所有同名函数,包括:
-
同一作用域中声明的同名函数;
-
通过 using 引入的同名函数;
-
通过 ADL(实参依赖查找)在实参关联命名空间中找到的同名函数;
-
函数模板(会先推导模板参数)。
第二步:确定可行函数(viable functions)
可行函数必须满足两个条件:
参数个数匹配(考虑默认参数后);
每个实参都能隐式转换到对应形参类型。
不满足任一条件的函数被淘汰。
第三步:选择最佳可行函数(best viable function)
对每个可行函数,为每个实参计算一个隐式转换序列(implicit conversion sequence),然后两两比较。
规则:
如果函数 A 对每个参数的转换都不比 B 差,且至少有一个参数的转换比 B 好,则 A 胜出。
如果找不到这样的函数,就是二义性(ambiguous),编译报错。
2. 隐式转换序列的等级
从好到差:
| 1. 精确匹配 | identity、左值到右值、数组到指针、函数到指针、限定转换 | int -> int,int[3] -> int*,int -> const int |
| 2. 提升 | 整型提升、浮点提升 | char -> int,short -> int,float -> double |
| 3. 标准转换 | 其他内置类型转换、指针转换、bool 转换 | int -> double,double -> int,T* -> void* |
| 4. 用户定义转换 | 通过转换构造函数或 operator T() | const char* -> std::string |
| 5. 省略号匹配 | … | f(…) |
注意:提升优于标准转换,这是很多重载解析结果的关键。
3. 常见特殊规则
3.1 非模板优先
普通函数和函数模板都能匹配且转换序列相同时,普通函数优先。
cpp
template<class T> void f(T);
void f(int);
f(1); // 调用 f(int),非模板优先
3.2 更特化的模板优先
两个模板都匹配时,选择更特化的那个。
cpp
template<class T> void f(T);
template<class T> void f(T*);
int x;
f(&x); // 调用 f(T*),更特化
3.3 二义性示例
cpp
void f(long);
void f(double);
f(1); // int -> long 和 int -> double 都是标准转换,二义性
3.4 多个参数的比较
对于多参数函数,必须整体比较:
cpp
void f(int, double);
void f(double, int);
f(1, 2); // 两个函数各有一个参数更好,二义性
#include <iostream>
#include <string>
// ================= 重载集合 =================
void f(int x) { std::cout << "f(int) <- " << x << "\\n"; }
void f(double x) { std::cout << "f(double) <- " << x << "\\n"; }
void f(char x) { std::cout << "f(char) <- " << x << "\\n"; }
void f(long x) { std::cout << "f(long) <- " << x << "\\n"; }
void f(const std::string& s) { std::cout << "f(std::string) <- " << s << "\\n"; }
void f(int x, int y) { std::cout << "f(int,int) <- " << x << "," << y << "\\n"; }
void f(int x, double y) { std::cout << "f(int,double) <- " << x << "," << y << "\\n"; }
int main() {
std::cout << "— 精确匹配 —\\n";
f(42); // f(int)
f(3.14); // f(double)
f('a'); // f(char)
f(42L); // f(long)
std::cout << "\\n— 提升 —\\n";
f(1.0f); // float -> double,调用 f(double)
f(short(7)); // short -> int,调用 f(int)
std::cout << "\\n— 用户定义转换 —\\n";
f("hello"); // const char* -> std::string,调用 f(std::string)
std::cout << "\\n— 多参数 —\\n";
f(1, 2); // f(int,int)
f(1, 2.0); // f(int,double)
f(1, 2.0f); // float -> double,调用 f(int,double)
return 0;
}
网硕互联帮助中心


评论前必须登录!
注册