What does the single ampersand after the parameter list of a member function declaration mean?
C++C++11C++ Problem Overview
From the answer here.
class wrap {
public:
operator obj() const & { ... } //Copy from me.
operator obj() && { ... } //Move from me.
private:
obj data_;
};
I know the &&
means that the member will be invoked when the object is an rvalue reference. But what does the single ampersand mean? How is it different than without the ampersand?
C++ Solutions
Solution 1 - C++
It means the member will be invoked when the object is an lvalue reference.
> [C++11: 9.3.1/5]:
A non-static member function may be declared with a ref-qualifier (8.3.5); see 13.3.1.
>
> [C++11: 13.3.1/4]:
For non-static member functions, the type of the implicit object parameter is
>
> - “lvalue reference to cv X
” for functions declared without a ref-qualifier or with the &
ref-qualifier
> - “rvalue reference to cv X
” for functions declared with the &&
ref-qualifier
>
> where X
is the class of which the function is a member and cv is the cv-qualification on the member function declaration. [..]
>
> (and some more rules that I can't find)
Without a ref-qualifier, the function can always be invoked, regardless of the value category of the expression through which you're invoking it:
struct foo
{
void bar() {}
void bar1() & {}
void bar2() && {}
};
int main()
{
foo().bar(); // (always fine)
foo().bar1(); // doesn't compile because bar1() requires an lvalue
foo().bar2();
foo f;
f.bar(); // (always fine)
f.bar1();
f.bar2(); // doesn't compile because bar2() requires an rvalue
}
Live demo (thanks Praetorian)
Solution 2 - C++
> But what does the single ampersand mean?
The function can only be called on an lvalue, not on an rvalue.
> How is it different than without the ampersand?
Without a ref-qualifier you can invoke the function on an lvalue or an rvalue.
With a ref-qualifier you can only call the function on the corresponding value category.
Solution 3 - C++
A function without a ref-qualifier can be called for both rvalue and lvalues. A function with a &&
ref-qualifier can only be called for rvalues. A function with a &
ref-qualifier can only be called for lvalues.
class No { void foo(); };
class L { void foo() &; };
class R { void foo() &&; };
No().foo(); // valid
No no; no.foo(); // valid
L().foo(); // invalid
L l; l.foo(); // valid
R().foo(); // valid
R r; r.foo(); // invalid
Unfortunately, I can only find this rule in 5.5/6, which applies only to pointer-to-member dereference expressions. I know it applies otherwise too.
Furthermore, you cannot overload on ref-qualifier vs no ref-qualifier, see 13.1/2 bullet 3. You can overload on &
vs &&
.
(And due to my fruitless search of the standard, LRiO's answer now has all that info too.)