97

Recently I was reading through the API of boost::optional and came across the lines:

T const& operator *() const& ;
T&       operator *() & ;
T&&      operator *() && ;

I also wrote my own program that defines member functions as const&, & and && (Note that I am not speaking about the return type, but the specifiers just before the semi-colons) and they seems to work fine.

I know what it means to declare a member function const, but can anyone explain what it means to declare it const&, & and &&.

0

2 Answers 2

75

const& means that this overload will be used only for const, non-const and lvalue objects, such as:

const A a = A();
*a;

& means that this overload will be used only for non-const objects:

A a;
*a;

&& means that this overload will be used only for rvalue objects:

*A();

For more information about this feature of the C++11 standard you can read this post: What is "rvalue reference for *this"?

Sign up to request clarification or add additional context in comments.

9 Comments

If it helps, I like to think of these qualifiers as applying to the *this object that is "secretly" passed in as the first argument of methods.
const& and & mean they will be used for a const and non-const lvalue. && will be used only for an rvalue, not necessarily a reference.
Actually, the const & can bind to pretty much anything, even an rvalue. Similar rules as apply to the binding of any parameter - const T& is kinda special - it can bind to anything that isn't volatile IIRC
@john_zac You're right in why they did it, and no, a compiler cannot introduce std::moves as it sees fit. It could break the class's invariants, RAII semantics etc. The only place in the standard where something similar is allowed is return, where returning as an rvalue is tried first.
@john_zac, these aren't quite "necessary", as you ask. But they provide certain optional optimizations. You could get away with just having T operator *(); - this would compile but it would have some weird consequences - *p = x wouldn't do what you expect it to do. I think the important thing is the return type - we want multiple overloads with different return types. Once you understand the desirability of different return types, then you see also that we need the qualifiers on the end to control which overload (and therefore which return type) is used for each call.
|
56

It is a member function ref-qualifiers; it is one of the features added in C++11. It is possible to overload non-static member functions based on whether the implicit this object parameter is an lvalue or an rvalue by specifying a function ref-qualifier (some details).

To specify a ref-qualifier for a non-static member function, you can either qualify the function with & or &&.

#include <iostream>
struct myStruct {
    void func() & { std::cout << "lvalue\n"; }
    void func() &&{ std::cout << "rvalue\n"; }
};
 
int main(){
    myStruct s;
    s.func();            // prints "lvalue"
    std::move(s).func(); // prints "rvalue"
    myStruct().func();   // prints "rvalue"
}

1 Comment

any use case for myStruct().func(); over s.func();? @Alper

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.