Adding a ref-qualifier to an operator will remove the possibility to do rvalue assignment
for example, compiling the following with 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;
}
will give you
$ 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); }
| ^~~~~~~~
you can of course "fix" this by adding an explicit &&
#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;
}
output
$ g++ -std=c++14 bar.cpp && ./a.out
13
But adding a const &
will also let you call +=
on the struct instance.
#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;
}
output
$ g++ -std=c++14 bar.cpp && ./a.out
14
To "fix" this, the const &&
must be explicitly deleted
#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;
}
output
$ 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;
| ^~~~~~~~
Why is this? Why do adding the ref-qualifier implicitly remove the rvalue assignment? But adding a cv-qualifier together with ref-qualifier seem to implicitly add the rvalue assignment?
I'm sure I'm missing something obvious here. But Google-Wan Kenobi doesn't seem to be able to help me understand.
Because rvalues could be bound to lvalue-reference to const
. Just same as the following code:
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
BTW: The overload qualified with rvalue-reference wins in overload resolution when calling on rvalues. That's why you mark it as delete
explicitly works as expected.