OMGtechy OMGtechy - 3 months ago 23
C++ Question

Forwarding references, ref qualifiers and template member functions

Take the following member function:

struct T {
template <typename X> void f(X&& x) { /* ... */ }
};


In this case,
x
is a forwarding reference because
&&
is used for the function parameters inside of a template. This is as expected.

Now take this function:

struct T {
template <typename X> void f(X&& x) && { /* ... */ }
};


I would expect that
this
would be treated in a similar manner; as a forwarding reference. Therefore, I would expect the following program to compile and run just fine:

#include <iostream>

struct T {
template <typename X>
bool operator<(X&& rhs) && {
std::cout << "&&" << std::endl;
return true;
}
};

int main() {
T t;
std::cout << (t < T()) << std::endl;
return 0;
}


But using GCC 4.8.4 and 6.0.1, it does not. Instead, I get the following:

rvalue.cpp: In function ‘int main()’:
rvalue.cpp:13:25: error: passing ‘T’ as ‘this’ argument of ‘bool T::operator<(X&&) && [with X = T]’ discards qualifiers [-fpermissive]
std::cout << (t < T()) << std::endl;


It would appear that
this
is not made a forwarding reference.
Is this correct or an error? Should
this
be treated as a forwarding reference? What part of the standard specifies this?

Answer

The two &&s` here are treated differently:

struct T {
    template <typename X> void f(X&& x) && { /* ... */ }
};

You are correct in that x is a forwarding reference. But the && on the right is a qualification on the object instance. In this case, f() can only be invoked if the object instance is an rvalue (perhaps adding to the confusion is that the first && takes x as a forwarding reference but the second && takes the implicit this argument as an rvalue reference). That is:

T().f(4); // ok

T t;
t.f(4); // error

This works the same way as const qualification does:

struct X { void f(); };
const X cx;
cx.f(); // error
Comments