C++ explicit修饰operator int时operator+匹配规则疑问
问题复现
类定义代码
class Yun { int q; friend Yun operator+(const Yun& a, const Yun& b) { Yun c = a; c.q += b.q; return c; } public: Yun(int i) :q(i) { } explicit operator int() { return q; } };
两个测试版本main函数
- 编译失败版本
int main() { Yun y(3); int w = y + 2; return 0; }
- 编译通过版本
int main() { Yun y(3); y+2; return 0; }
疑问1解答
你以为编译器没走「把2通过Yun(int)转成Yun、匹配友元operator+」的路径?其实它真选了这个方案,编译失败的锅根本不在+的重载决议阶段,是后面给w赋值的时候出的问题。
整个int w = y + 2;的执行是拆成两步走的:
- 先算
y + 2这个子表达式:编译器会先把所有能用上的operator+都拉出来筛一遍:- 第一个候选就是你写的友元函数
Yun operator+(const Yun&, const Yun&):左边的y是Yun类型,直接绑const引用属于精确匹配;右边的2是int,Yun(int)没加explicit,本来就支持隐式转Yun,参数匹配完全合法,是可行候选。 - 第二个候选是编译器内置的
int operator+(int, int):要走这个路径得把y从Yun隐式转成int,但你给operator int()加了explicit,隐式转换场景下这个转换函数根本不会被考虑,所以这个候选在参数筛查阶段就直接被踢出去了。
筛完就剩友元函数一个可行选项,编译器肯定选它,算完返回一个Yun类型的临时对象。
- 第一个候选就是你写的友元函数
- 拿上一步得到的Yun临时对象给int类型的w做拷贝初始化:拷贝初始化是典型的隐式转换语境,要求Yun能隐式转成int,但负责转int的
operator int()被explicit修饰了,不让隐式调用,这一步直接卡死,最后就报编译错误。
很多人会误会编译器没选自定义operator+,主要是被编译器的错误提示带偏了——编译器报错的时候会把所有试过走不通的路径都列出来(包括那个被淘汰的内置operator+),看起来好像在两个方案里纠结,其实根本不是。
疑问2解答
把赋值去掉、只留y+2;的时候,整个表达式只需要跑完上面说的第一步就完事了:
重载决议还是选那个友元operator+,2隐式转成临时Yun对象传参,算完返回一个Yun临时对象。这个临时对象没有被赋值给任何变量,也不需要转成别的类型参与其他运算,属于算完就丢的纯右值,全程根本轮不到调用operator int(),自然碰不到explicit的限制,当然能正常编译通过。
可以自己写个验证:把第一版main的赋值改成显式转换,写
int w = (int)(y + 2);,代码也能正常编过——因为显式类型转换的场景下,explicit修饰的转换函数是允许调用的。
内容的提问来源于stack exchange,提问作者air
相关产品推荐
相关产品推荐

