【问题标题】:Ambiguous overload for operator= using move assign and pass by value copy assign运算符 = 使用移动分配和按值复制分配传递的模棱两可的重载
【发布时间】:2026-01-14 06:35:01
【问题描述】:

如果我定义了一个复制赋值运算符,该运算符使用 thing 类的值传递调用复制构造函数:

thing& operator= (thing x) {

和同一类的移动赋值运算符:

thing& operator= (thing&& x) {

尝试调用移动赋值会导致 gcc 出错:

error: ambiguous overload for ‘operator=’ (operand types are ‘thing’ and ‘std::remove_reference<thing&>::type {aka thing}’)

但是,如果复制分配改为使用按引用传递:

thing& operator= (thing& x) {

编译没问题,两个运算符都可以调用。为什么是这样?

完整的C++11测试代码:

#include <iostream>
#include <utility>

using namespace std;

class thing {
    public:
        thing () { }
        thing (thing& x) {
            cout << "Copy constructor.\n";
        }
        thing (thing&& x) {
            cout << "Move constructor.\n";
        }
        thing& operator= (thing x) {
            cout << "Copy assign using pass by value.\n";
            return *this;
        }
        thing& operator= (thing&& x) {
            cout << "Move assign.\n";
            return *this;
        }
};


int main (void) {
    thing a, b;
// Invoke move assignment:
    a = move(b);
    return 0;
}                        

【问题讨论】:

  • 在重载解析中有一个特殊规则,即A 类型的右值更喜欢绑定到A&amp;&amp; 而不是A&amp;A&amp;&amp;A 没有对应的规则。
  • @T.C. A&amp; 不是必须是左值吗?
  • 其实是的,我应该写const A&amp;A&amp; 只绑定左值。

标签: c++ g++ move-semantics


【解决方案1】:
  • 调用move(b)会返回rvalue

  • operator=(thing &amp;&amp;x)operator=(thing x) 都可以接受 rvalues 作为输入。

  • 因此,这两个重载是模棱两可的,编译器理所当然地抱怨,因为它无法在它们之间进行选择。

【讨论】:

  • +1 我得到了第二点(关于右值作为输入),但第一个点的相关性是什么?
  • @goldilocks 模棱两可的调用是在a = move(b);,这与调用a.operator=(move(b)) 相同。 std::move 返回一个引用其输入的rvalue 引用(即b)。编译器看到std::move 的返回值是一个rvalue 引用,并且在重载解析期间试图找到哪个重载适合将std::move 返回的结果作为输入。不幸的是,正如@T.C 已经评论的那样,没有规则可以区分这两个重载。因此,您会收到一个模棱两可的调用错误。
  • 这个问题有解决办法吗?
最近更新 更多