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

临时/匿名对象与具名对象的运算符查找规则是否存在差异?

具名对象与临时对象调用基类友元运算符的差异解析

核心原因:左值引用参数的绑定限制

你的代码中,基类Base定义的友元operator+=第一个参数是非const左值引用:

friend DerivedType& operator +=(DerivedType& lhs, const integertype& rhs)

C++中,非const左值引用只能绑定到左值(具名对象),无法绑定到临时右值对象。这是导致两种调用场景差异的根本原因,而非临时对象的查找规则特殊。


未定义COMPLEX宏(mytype为double)的场景分析

1. 临时对象调用:Wrapper(2.0) += 3u

临时对象Wrapper(2.0)是右值,无法绑定到基类友元operator+=的左值引用参数,因此该友元运算符直接被排除在候选集之外。

编译器只能从Wrapper的成员运算符中选择:

  • Wrapper& operator+=(const Wrapper&):需要将3u通过用户定义转换(Wrapper(const unsigned&)构造)转为Wrapper
  • Wrapper& operator+=(const double&):3u可通过标准转换转为double(标准转换优先级高于用户定义转换)

因此编译器选择后者,输出wrapper mytype version。

2. 具名对象调用:t_MyWrapper += 3u

具名对象t_MyWrapper是左值,可以绑定到基类友元operator+=的左值引用参数。此时候选集包括:

  • 基类友元operator+=:参数完全匹配(无需任何转换),优先级最高
  • Wrapper的两个成员运算符:均需要参数转换

因此编译器优先选中基类友元运算符,先输出base += version;友元函数内部调用lhs += mytype(rhs),即调用Wrapper的operator+=(const double&),再输出wrapper mytype version。


定义COMPLEX宏(mytype为std::complex<double>)的场景分析

1. 临时对象调用:Wrapper(2.0) += 3u

同样,基类友元operator+=因左值引用无法绑定临时右值,被排除在候选之外。剩下的候选:

  • Wrapper& operator+=(const Wrapper&):3u需通过用户定义转换转为Wrapper
  • Wrapper& operator+=(const std::complex<double>&):3u需通过用户定义转换(std::complex的算术类型构造函数)转为std::complex<double>

两个候选的转换优先级相同(均为用户定义转换序列),因此编译器报歧义错误。

2. 具名对象调用

具名对象是左值,基类友元operator+=会被纳入候选,且参数完全匹配(无需转换),优先级高于需要转换的成员运算符,因此不会出现歧义,编译正常。


验证与解决方案

  • 如果将基类友元operator+=的第一个参数改为const DerivedType&(可绑定右值)或DerivedType&&(专门绑定右值),临时对象也能调用该友元运算符,消除差异。
  • 将运算符移至Wrapper类作为成员函数时,成员函数的this指针可指向右值(除非用ref-qualifier限制),因此临时对象可正常调用;若改为Wrapper的友元函数,仍需注意参数的引用类型是否支持右值绑定。
  • 移除Wrapper(const unsigned&)构造函数后,COMPLEX模式下临时对象的候选仅剩operator+=(const mytype&),消除歧义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:20:56