为什么 ref-qualifier 和 cv-qualifier 在运算符重载上允许右值赋值?

Why do ref-qualifier together with cv-qualifier on operator overloading allow rvalue assignment?

向运算符添加引用限定符将消除进行右值赋值的可能性

例如用g++ -std=c++14 bar.cpp && ./a.out

编译如下
#include <cstdio>

struct foo
{
    void operator+=(int x) & { printf("%d\n", x+2); }  
};

int main()
{
    foo() += 10;
}

会给你

$ g++ -std=c++14 bar.cpp && ./a.out
bar.cpp: In function ‘int main()’:
bar.cpp:14:14: error: passing ‘foo’ as ‘this’ argument discards qualifiers [-fpermissive]
   14 |     foo() += 10;
      |              ^~
bar.cpp:6:10: note:   in call to ‘void foo::operator+=(int) &’
    6 |     void operator+=(int x) & { printf("%d\n", x+2); }
      |          ^~~~~~~~

您当然可以通过添加明确的 &&

来“解决”这个问题
#include <cstdio>

struct foo
{
    void operator+=(int x) & { printf("%d\n", x+2); }  
    void operator+=(int x) && { printf("%d\n", x+3); }  
};

int main()
{
    foo() += 10;
}

输出

$ g++ -std=c++14 bar.cpp && ./a.out
13

但是添加 const & 也可以让您在结构实例上调用 +=

#include <cstdio>

struct foo
{
    void operator+=(int x) & { printf("%d\n", x+2); }  
    void operator+=(int x) const & { printf("%d\n", x+4); }  
};

int main()
{
    foo() += 10;
}

输出

$ g++ -std=c++14 bar.cpp && ./a.out
14

要“修复”此问题,必须明确删除 const &&

#include <cstdio>

struct foo
{
    void operator+=(int x) & { printf("%d\n", x+2); }  
    void operator+=(int x) const & { printf("%d\n", x+4); }  
    void operator+=(int x) const && = delete;
};

int main()
{
    foo() += 10;
}

输出

$ g++ -std=c++14 bar.cpp && ./a.out
bar.cpp: In function ‘int main()’:
bar.cpp:14:14: error: use of deleted function ‘void foo::operator+=(int) const &&’
   14 |     foo() += 10;
      |              ^~
bar.cpp:9:10: note: declared here
    9 |     void operator+=(int x) const && = delete;
      |          ^~~~~~~~

这是为什么?为什么添加 ref 限定符会隐式删除右值赋值?但是添加 cv-qualifier 和 ref-qualifier 似乎隐含地添加了右值赋值?

我确定我在这里遗漏了一些明显的东西。但是Google-Wan Kenobi好像不能帮我理解。

因为右值可以绑定到 const 的左值引用。就像下面的代码一样:

foo& r1 = foo();       // invalid; rvalues can't be bound to lvalue-reference to non-const
const foo& r2 = foo(); // fine; rvalues can be bound to lvalue-reference to const

顺便说一句:在调用右值时,用右值引用限定的重载在重载决议中获胜。这就是为什么您将其标记为 delete 明确按预期工作。