提问人:Tom_DB 提问时间:11/23/2022 更新时间:11/23/2022 访问量:60
临时/匿名对象的运算符查找是否不同?
Is operator lookup different for temporary/anonymous objects?
问:
我试图理解为什么命名对象和临时对象(匿名?)对象在查找基类中定义的运算符时行为似乎不同。在下面的代码中,我围绕一个变量“mytype”制作了一个包装器,我想通过编译器定义在 double 和 std::complex 之间切换。对于这个包装器,我想添加一个使用基类型(类似于 boost::operators)的运算符。我的兴趣在于“main”中两条(诚然相当强迫)cout 线之间的区别。
#include <iostream>
#include <cmath>
#include <complex>
#ifdef COMPLEX
typedef std::complex<double> mytype;
#else
typedef double mytype;
#endif
template <typename DerivedType, typename integertype>
struct Base
{
friend DerivedType& operator +=(DerivedType& lhs, const integertype& rhs)
{
std::cout << "base += version" << std::endl;
return lhs += mytype(rhs);
}
};
struct Wrapper : public Base<Wrapper, unsigned>
{
Wrapper(const mytype& rhs) : m_value(rhs) {}
Wrapper(const unsigned& rhs) : Wrapper(mytype(rhs)) {}
Wrapper& operator += (const Wrapper& rhs)
{
std::cout << "wrapper version" << std::endl;
m_value += rhs.m_value;
return *this;
}
Wrapper& operator += (const mytype& rhs)
{
std::cout << "wrapper mytype version" << std::endl;
m_value += rhs;
return *this;
}
mytype m_value;
};
int main()
{
std::cout << (Wrapper(2.0) += 3u).m_value << std::endl;
Wrapper t_MyWrapper(2.0);
std::cout << (t_MyWrapper += 3u).m_value << std::endl;
}
如果我在没有-DCOMPLEX的情况下编译,我会得到以下输出:
wrapper mytype version
5
base += version
wrapper mytype version
5
据我所知,main 中的第一个输出忽略了 Base 的运算符+=(Wrapper&, const unsigned&)。相反,它将 unsigned 提升为 double(这优先于转换为 Wrapper),并调用运算符+=(Wrapper& const double&)。但是,“命名对象”确实从基类型调用运算符。使用 -DCOMPLEX 进行编译会导致编译错误:
SimplifiedProblem.cxx: In function ‘int main()’:
SimplifiedProblem.cxx:47:32: error: ambiguous overload for ‘operator+=’ (operand types are ‘Wrapper’ and ‘unsigned int’)
47 | std::cout << (Wrapper(2.0) += 3u).m_value << std::endl;
| ~~~~~~~~~~~~~^~~~~
SimplifiedProblem.cxx:28:14: note: candidate: ‘Wrapper& Wrapper::operator+=(const Wrapper&)’
28 | Wrapper& operator += (const Wrapper& rhs)
| ^~~~~~~~
SimplifiedProblem.cxx:35:14: note: candidate: ‘Wrapper& Wrapper::operator+=(const mytype&)’
35 | Wrapper& operator += (const mytype& rhs)
| ^~~~~~~~
考虑到将 unsigned 转换为 std::complex 并不比转换为“Wrapper”(也不是标量类型)“更好”,编译错误是有道理的,但我想了解为什么不使用基类型的运算符。
将运算符+=(Wrapper&, const unsigned&) 直接移动到包装器可以避免此问题,删除构造函数 Wrapper(const unsigned&) 可以解决 -DCOMPLEX 时的歧义。但是我想知道临时对象查找的规则是否不同,或者是否还有其他原因导致了这种行为。
答:
文本隐式转换为 a,因此编译器标记给您的行中的两个重载都是可能的候选者。3u
Wrapper
operator+=
一个简单的解决方案是用显式
标记两个构造函数。然后,它们永远不会允许隐式转换为 a,但始终要求您键入转换,就像在第一行中所做的那样。Wrapper
Wrapper
main
上一个:匿名对象作为泛型类型
评论
const
DerivedType& lhs
3u
void f(int&) {}; int main() { f(1); }
friend
const
const