Reputation: 42255
#include <type_traits>
#include <utility>
int main()
{
auto f1 = [](auto&& e) -> auto
{
return e;
};
auto f2 = [](auto&& e) -> auto&
{
return e;
};
auto f3 = [](auto&& e) -> auto&&
{
return e;
};
auto f4 = [](auto&& e) -> decltype(auto)
{
return e;
};
int n{};
f1(std::move(n)); // ok
f2(std::move(n)); // ok
f3(std::move(n)); // ok
f4(std::move(n)); // error
}
clang's error message:
error : rvalue reference to type 'int' cannot bind to lvalue of type 'int'
To me, decltype(auto)
has only three possible deduced types:
auto
auto&
auto&&
Why is f4
error while all of the other three are ok?
Upvotes: 2
Views: 640
Reputation: 11250
It's a GCC bug.
decltype(auto) = e
is equivalent to decltype(e)
and yield the declared type of e
.
auto
works as template parameter which mean that auto&&
is the same as T&&
(forwarding reference) for an invented template parameter.
For f1 the return type is deduced to int
.
For f2 the return type auto&
is equivalent to T&
with deduced T=int
which is the type of the lvalue e
, here you're binding int&
to e
.
For f3 consider this:
auto&& t = n;
static_assert(std::is_same_v<decltype(t), int&>); // true
for both the return of f3
, auto&&
is equivalent to the invented template parameter T&&
which is a forwarding reference, this initialized with an lvalue, yield T&
with deduced T=int
, then again ... binding int&
to the lvalue e
.
Now for f4 consider this:
int&& r = 9;
static_assert(std::is_same_v<decltype(r), int&&>); // true (1)
decltype(auto) t = r; // fail with the same error you got.
the parameter of f4
is also a forwarding reference T&&
that is initialized with the xvalue std::move(n)
, this deduce T=int
resulting in a parameter int&& e
. A return type as decltype(auto)
with return e
means that the actual return is decltype(e)
, then as you can see (1) is true, the same hold for decltype(e)
, this means that the actual return of f4
is int&&
... and there's the problem, f4
is trying to bind a rvalue int&&
to an lvalue e
which is prohibited.
You can also take a look at @StoryTeller's answer for the GCC bug.
Upvotes: 4