23

I have seen in an anwser there: Is returning by rvalue reference more efficient?

The member function definition:

Beta_ab const& getAB() const& { return ab; }

I am familiar with the cv-qualifier (const) on member functions, but not const&.

What does the last const& mean?

Community
  • 1
  • 1
galinette
  • 8,896
  • 2
  • 36
  • 87
  • Related/duplicate: http://stackoverflow.com/q/21861148/420683 – dyp Apr 11 '14 at 12:25
  • Note that the accepted answer's example is a non-const `&` qualifier, whereas the question is about a `const&` qualifier. The example `kitten{}.pet();` would actually compile if `pet` were qualified as `void pet() const&;`. To forbid this we'd need to add the additional line: `void pet() const&& = delete;`. – jcai Jan 10 '22 at 22:12

2 Answers2

36

The & is a ref-qualifier. Ref-qualifiers are new in C++11 and not yet supported in all compilers, so you don't see them that often currently. It specifies that this function can only be called on lvalues (and not on rvalues):

#include <iostream>

class kitten
{
private:
    int mood = 0;

public:
    void pet() &
    {
        mood += 1;
    }
};

int main()
{
    kitten cat{};
    cat.pet(); // ok

    kitten{}.pet(); // not ok: cannot pet a temporary kitten
}

Combined with the cv-qualifier const, it means that you can only call this member function on lvalues, and those may be const.

dyp
  • 38,334
  • 13
  • 112
  • 177
  • 4
    You might add that this is a new feature in C++11, not yet supported by all compilers, and that you're not likely to see it in existing code (yet). – James Kanze Apr 11 '14 at 11:44
  • 3
    The relevance of this construction is that it forbids things like `Beta_ab const & danger = Beta_ab().getAB();` – Kerrek SB Apr 11 '14 at 11:46
  • OK, I see. So if supported by the compiler, this should be set on every const member function returning a const reference to a member variable? I have lots of these and occasionally had bugs related to using them on a rvalue. – galinette Apr 11 '14 at 12:12
  • 1
    You should remove the first half of the answer! Most people know that already, and this would make the important part of your answer visible without scrolling down. First reaction by reading is : ughh ok I already know what a const modifier does on a member function... – galinette Apr 11 '14 at 12:15
  • 1
    Good point. Removing that part. – dyp Apr 11 '14 at 12:16
  • Arghhh I'm with gcc 4.8.0 and only 4.8.1 supports this... http://isocpp.org/blog/2013/05/gcc-4.8.1-released-c11-feature-complete – galinette Apr 11 '14 at 12:17
  • I agree also with your other point: When returning a *reference* to some object bound to the lifetime of your own object, you get the usual lifetime issues. Under some circumstances, that's acceptable, but per default, it should be qualified with an lvalue-ref. (That's btw what Kerrek was pointing out.) – dyp Apr 11 '14 at 12:22
  • @dyp : The question is now more clear also! – galinette Apr 11 '14 at 12:23
10

We know that in this code...

Beta_ab const& getAB() const { return ab; }
                       ^^^^^

The highlighted const means that the member function may be called upon a const object. A member function can always be called upon a non-const object regardless of the function's cv-qualification.

So in this code...

Beta_ab const& getAB() const & { return ab; }
                             ^

We should expect that the highlighted & also says something about what kinds of objects this member function is allowed to be called upon. We would be correct; in C++11, this says that the member function may only be called upon lvalues.

Beta_ab const& getAB() const& { return ab; }
Beta_ab &&     getAB() &&     { return ab; }

In the above example, the first overload is invoked on lvalues, and the second overload is invoked on non-const rvalues. Similar to the following more familiar example, with qualifiers applied to ordinary function parameters:

void setAB(AB const& _ab) { ab = _ab; }
void setAB(AB &&     _ab) { ab = std::move(_ab); }

It works slightly differently for ordinary parameters though, as in this example, the first overload would accept an rvalue if the second overload were removed.

Oktalist
  • 14,336
  • 3
  • 43
  • 63