What does the single ampersand after the parameter list of a member function declaration mean?

C++C++11

C++ 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.)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2005303View Question on Stackoverflow
Solution 1 - C++Lightness Races in OrbitView Answer on Stackoverflow
Solution 2 - C++Jonathan WakelyView Answer on Stackoverflow
Solution 3 - C++Sebastian RedlView Answer on Stackoverflow