The &
or &&
after the method serve a special purpose: they serve as a ref value qualifier.
In a sense, all of the things you can put after a function's argument declarations (i.e. after the )
of the parameters) means "only use this method when *this
has these qualities".
Most typically usage here is const
qualifying: only calling an override in a const context:
class Widget {
void foo() {
cout << "Calling mutable foo\n";
}
void foo() const {
cout << "Calling const foo\n";
}
};
The same thing can be done with &&
or &
, to tell the compiler to select those overrides when *this
has matching qualifiers.
But why would you want to do this?
This is useful when you want to differentiate between one of the following:
- Give out a reference to some internal data in the normal lvalue case
- Copy out the data in the case where
*this
is an rvalue reference and will not outlive the calling code's reference.
A common example that bites a lot of people is the use in for loops.
Consider the following code (building on your Widget
example):
Widget buildWidget() { return Widget(); }
int main() {
for (auto i : buildWidget().data()) {
cout << i << '\n';
}
return 0;
}
In this case, the &&
override would be called because the Widget
object return by buildWidget
does not have a name, and is this an rvalue reference.
In concrete terms, as soon as the call to data()
is done, the underlying Widget
object (unnamed here) is going to immediately die (it's lifetime will end). If this &&
override didn't exist, the lvalue reference into its data
member would point to a destructed object. This would be undefined behavior.
In general, this rvalue ref qualifying thing is not a common thing. It really only needs to be used when you run into a situation like this (often when you want to return a value by copy when *this
may be destructed after the call).