Reputation: 8220
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?
Upvotes: 1
Views: 363
Reputation: 303057
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 object parameter 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
Upvotes: 3
Reputation: 361472
The member operator<() &&
can be called on rvalue only, so the following:
t < T()
is not going to work, because t
is not rvalue — it is lvalue.
The following should work:
std::move(t) < T()
and this too:
T{} < T{}
Note that I've used {}
as I'm more comfortable with them and they work without much surprise.
Upvotes: 0
Reputation: 180630
The reference qualifier at the end of the function states that operator<
should only be called when the LHS is a temporary. Remember a operator can be called like any other member function so what you have is
t.operator<(T())
and t
is not a temporary.
If we change your example to
std::cout << (T() < t) << std::endl;
Then it works just fine as the object you are calling the operator<
on is a temporary object.
Upvotes: 2