What does the & (ampersand) at the end of member function signature mean? - c++

I can't remember which talk it was, but recently I watched some talks from CppCon 2017 and there someone mentioned as some kind of side-note, that the only true way of overloading operator= would be in the following fashion:
class test {
public:
test& operator=(const test&) &;
};
He explicitly emphasized the trailing & but didn't say what it does.
So what does it do?

Ref-qualifiers - introduced in C++11
Ref-qualifiers is not C++17 feature (looking at the tag of the question), but was a feature introduced in C++11.
struct Foo
{
void bar() const & { std::cout << "const lvalue Foo\n"; }
void bar() & { std::cout << "lvalue Foo\n"; }
void bar() const && { std::cout << "const rvalue Foo\n"; }
void bar() && { std::cout << "rvalue Foo\n"; }
};
const Foo&& getFoo() { return std::move(Foo()); }
int main()
{
const Foo c_foo;
Foo foo;
c_foo.bar(); // const lvalue Foo
foo.bar(); // lvalue Foo
getFoo().bar(); // [prvalue] const rvalue Foo
Foo().bar(); // [prvalue] rvalue Foo
// xvalues bind to rvalue references, and overload resolution
// favours selecting the rvalue ref-qualifier overloads.
std::move(c_foo).bar(); // [xvalue] const rvalue Foo
std::move(foo).bar(); // [xvalue] rvalue Foo
}
Note that an rvalue may be used to initialize a const lvalue reference (and in so expanding the lifetime of the object identified by the rvalue), meaning that if we remove the rvalue ref-qualifier overloads from the example above, then the rvalue value categories in the example will all favour the remaining const & overload:
struct Foo
{
void bar() const & { std::cout << "const lvalue Foo\n"; }
void bar() & { std::cout << "lvalue Foo\n"; }
};
const Foo&& getFoo() { return std::move(Foo()); }
int main()
{
const Foo c_foo;
Foo foo;
// For all rvalue value categories overload resolution
// now selects the 'const &' overload, as an rvalue may
// be used to initialize a const lvalue reference.
c_foo.bar(); // const lvalue Foo
foo.bar(); // lvalue Foo
getFoo().bar(); // const lvalue Foo
Foo().bar(); // const lvalue Foo
std::move(c_foo).bar(); // const lvalue Foo
std::move(foo).bar(); // const lvalue Foo
}
See e.g. the following blog post for for a brief introduction:
Andrzej's C++ blog - Ref-qualifiers
rvalues cannot invoke non-const & overloads
To possibly explain the intent of your recollected quote from the CppCon talk,
"... that the only true way of overloading operator= ..."
we visit [over.match.funcs]/1, /4 & /5 [emphasis mine]:
/1 The subclauses of [over.match.funcs] describe the set of candidate functions and the argument list submitted to overload
resolution in each context in which overload resolution is used. ...
/4 For non-static member functions, the type of the implicit object parameter is
(4.1) — “lvalue reference to cv X” for functions declared without a ref-qualifier or with the & ref-qualifier
(4.2) — “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. ...
/5 ... For non-static member functions declared without a ref-qualifier, an additional rule applies:
(5.1) — even if the implicit object parameter is not const-qualified, an rvalue can be bound to the parameter as long as
in all other respects the argument can be converted to the type of the
implicit object parameter. [ Note: The fact that such an argument is
an rvalue does not affect the ranking of implicit conversion
sequences. — end note ]
From /5 above, the following overload (where the explicit & ref-qualifier has been omitted)
struct test
{
test& operator=(const test&) { return *this }
}
allows assigning values to r-values, e.g.
int main()
{
test t1;
t1 = test(); // assign to l-value
test() = t1; // assign to r-value
}
However, if we explicitly declare the overload with the & ref-qualifier, [over.match.funcs]/5.1 does not apply, and as long we do not supply an overload declared with the && ref-qualifier, r-value assignment will not be allowed.
struct test
{
test& operator=(const test&) & { return *this; }
};
int main()
{
test t1;
t1 = test(); // assign to l-value
test() = t1; // error [clang]: error: no viable overloaded '='
}
I won't place any opinion as to whether explicitly including the & ref-qualifier when declaring custom assignment operator overloads is "the only true way of overload operator=", but would I dare to speculate, then I would guess that the intent behind such a statement is the exclusion of to-r-value assignment.
As a properly designed assignment operator should arguably never be const (const T& operator=(const T&) const & would not make much sense), and as an rvalue may not be used to initialize a non-const lvalue reference, a set of overloads for operator= for a given type T that contain only T& operator=(const T&) & will never proviade a viable overload that can be invoked from a T object identified to be of an rvalue value category.

As per http://en.cppreference.com/w/cpp/language/member_functions
the & following your member function declaration is lvalue ref-qualifier.
In other words, it requires this to be an l-value (the implicit object parameter has type lvalue reference to cv-qualified X).
There is also &&, which requires this to be an r-value.
To copy from documentation (const-, volatile-, and ref-qualified member functions):
#include <iostream>
struct S {
void f() & { std::cout << "lvalue\n"; }
void f() &&{ std::cout << "rvalue\n"; }
};
int main(){
S s;
s.f(); // prints "lvalue"
std::move(s).f(); // prints "rvalue"
S().f(); // prints "rvalue"
}

Related

friend functions with const parameters

I got to know that to make a friend function, friend function should be explicitly declared in enclosing scope or take an argument of its class. However, this one seems to be a caveat, I am failed to understand. Why does the call to f1(99) not works?
class X {
public:
X(int i) {
std::cout << "Ctor called" << std::endl;
}
friend int f1(X&);
friend int f2(const X&);
friend int f3(X);
};
int f1(X& a) {
std::cout << "non-const called" << std::endl;
}
int f2(const X& a) {
std::cout << "const called" << std::endl;
}
int f3(X a) {
std::cout << "object called" << std::endl;
}
int main() {
f1(99);
f2(99);
f3(99);
}
You're calling the functions with argument 99; but all the functions expect an X. 99 could convert to X implicitly, but the converted X is a temporary object and can't be bound to lvalue-reference to non-const.
The temporary object could be bound to lvalue-reference to const (and also rvalue-reference since C++11), then f2(99); works. And it could be copied to the parameter of f3, then f3(99) works too.
The effects of reference initialization are:
Otherwise, if the reference is lvalue reference to a non-volatile const-qualified type or rvalue reference (since C++11):
Otherwise, object is implicitly converted to T. The reference is bound to the result of the conversion (after materializing a temporary) (since C++17). If the object (or, if the conversion is
done by user-defined conversion, the result of the conversion
function) is of type T or derived from T, it must be equally or less
cv-qualified than T, and, if the reference is an rvalue reference, must not be an lvalue (since C++11).

What is `&` in `function() const &` in c++? [duplicate]

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 &&.
const& means, that this overload will be used only for const, non-const and lvalue object.
const A a = A();
*a;
& means, that this overload will be used only for non-const object.
A a;
*a;
&& means, that this overload will be used only for rvalue object.
*A();
for more information about this feature of C++11 standard you can read this post What is "rvalue reference for *this"?
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"
}

Can we implement a different function body in a class for when the function is called from an anonymous object? [duplicate]

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 &&.
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"?
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"
}

const& , & and && specifiers for member functions in C++

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 &&.
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"?
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"
}

Why is there ambiguity using reference-qualifiers on overloaded methods? [duplicate]

While working with ref-qualified function overloads, I'm getting different results from GCC (4.8.1) and Clang (2.9 and trunk). Consider the following code:
#include <iostream>
#include <utility>
struct foo
{
int& bar() &
{
std::cout << "non-const lvalue" << std::endl;
return _bar;
}
//~ int&& bar() &&
//~ {
//~ std::cout << "non-const rvalue" << std::endl;
//~ return std::move(_bar);
//~ }
int const& bar() const &
{
std::cout << "const lvalue" << std::endl;
return _bar;
}
int const&& bar() const &&
{
std::cout << "const rvalue" << std::endl;
return std::move(_bar);
}
int _bar;
};
int main(int argc, char** argv)
{
foo().bar();
}
Clang compiles it and outputs "const rvalue", while GCC thinks this is an ambiguous call with the two const-qualified functions both being best viable candidates. If I provide all 4 overloads, then both compilers output "non-const rvalue".
I would like to know which compiler --if any-- is doing the right thing, and what are the relevant standard pieces in play.
Note: The reason this actually matters is that the real code declares both const-qualified functions as constexpr. Of course, there is no output to std::cout and static_cast is used instead of std::move, so that they are valid constexpr definitions. And since in C++11 constexpr still implies const, the overload commented out in the sample code cannot be provided as it would redefine the const-qualified rvalue overload.
Firstly, the implicit object parameter is treated as a normal parameter as per 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.
So what you are asking is equivalent to the following:
void bar(foo&);
void bar(foo&&);
void bar(const foo&);
void bar(const foo&&);
int main()
{
bar(foo());
}
The expression foo() is a class prvalue.
Secondly, the non-const lvalue reference version is not viable, as a prvalue cannot bind to it.
This leaves us with three viable functions for overload resolution.
Each has a single implicit object parameter (const foo&, foo&& or const foo&&), so we must rank these three to determine the best match.
In all three case it is a directly bound reference binding. This is described in declarators/initialization (8.5.3).
The ranking of the three possible bindings (const foo&, foo&& and const foo&&) is described in 13.3.3.2.3:
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if
S1 and S2 are reference bindings and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier [this exception doesn't apply here, they all have ref-qualifiers], and S1 binds an rvalue reference to an rvalue [a class prvalue is an rvalue] and S2 binds an lvalue reference.
This means that both foo&& and const foo&& are better then const foo&.
S1 and S2 are reference bindings, and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
This means that foo&& is better than const foo&&.
So Clang is right, and it is a bug in GCC. The overload ranking for foo().bar() is as follows:
struct foo
{
int&& bar() &&; // VIABLE - BEST (1)
int const&& bar() const &&; // VIABLE - (2)
int const& bar() const &; // VIABLE - WORST (3)
int& bar() &; // NOT VIABLE
int _bar;
};
The bug in GCC seems to apply purely to implicit object parameters (with ref-qualifiers), for a normal parameter it seems to get the ranking correct, at least in 4.7.2.