使用移动赋值从算术运算符重载返回const值

tas*_*oor 8 c++ c++11

假设我有以下最小的示例类:

#include <iostream>

class Foo {
public:
    Foo() = default;

    Foo(const Foo&) = default;
    Foo(Foo&&) noexcept = default;

    Foo& operator=(const Foo& rhs) {
        std::cout << "copy\n";

        return *this;
    }

    Foo& operator=(Foo&& rhs) noexcept {
        std::cout << "move\n";

        return *this;
    }

    Foo operator+(const Foo& rhs) const {
        Foo x; // with some calculation

        return x;
    }
};

int main() {
    Foo a, b, c;

    a = b + c;
}
Run Code Online (Sandbox Code Playgroud)

move按预期打印.现在,根据有效的C++项目3,我应该返回const Foooperator+避免类似构造a + b = c,即:

// To avoid a + b = c
const Foo operator+(const Foo& rhs) const {}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这突然开始调用复制赋值而不是移动赋值运算符.[我在Ubuntu上使用gcc 4.8.4,但它可能与编译器无关]

如何确保a + b = c无法编译并同时调用移动分配a = b + c?或者随着移动语义的引入,有没有办法在同一时间实现它们?

tas*_*oor 2

我最终使用了 Caninonos 在评论中和 max66 在现已删除的答案中指出的左值引用限定符(但 10k 用户可以看到它)。

Foo& operator=(const Foo& rhs) & {}
Foo& operator=(Foo&& rhs) & noexcept {}
Run Code Online (Sandbox Code Playgroud)

它实现起来很简单,并且提供了更好的接口设计,因为分配给任何其他左值听起来没有意义,并且可能是错误的来源。

但需要注意的是,写错的可能性a + b = c很低。此外,编译器生成的赋值运算符不是左值引用限定的,我们可以a + b = c使用标准类型编写,例如 withstd::string或 with std::complex