Because this is a language-lawyer question. The rules for lifetime extension are in [class.temporary]. The wording from C++11 to C++14 to C++17 didn't change in a way that is relevant to this particular question. The rule is:
There are [two/three†] contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when a default constructor is called to initialize an element of an array [...]†
The [second/third†] context is when a reference is bound to a temporary. The temporary to which the reference is
bound or the temporary that is the complete object of a subobject to which the reference is bound persists
for the lifetime of the reference except:
— A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion
of the full-expression containing the call.
This expression:
std::forward_as_tuple([](int v){ std::cout << v << std::endl; })
involves binding a reference (the parameter in forward_as_tuple
) to a prvalue (the lambda-expression), which is explicitly mentioned in C++11/14 as a context which creates a temporary:
Temporaries of class type are created in various contexts: binding a reference to a prvalue, [...]
which in C++17 is worded as:
Temporary objects are created
(1.1) — when a prvalue is materialized so that it can be used as a glvalue (4.4),
Either way, we have a temporary, it's bound to a reference in a function call, so the temporary object persists until the completion of the full-epxression containing the call.
So this is okay:
std::get<0>(std::forward_as_tuple(
[](int v){ std::cout << v << std::endl; }
))(6);
But this calls through a dangling reference:
auto t = std::forward_as_tuple(
[](int v){ std::cout << v << std::endl; }
);
std::get<0>(t)(6);
because the lifetime of the temporary function object ended at the end of the statement initializing t
.
Note that this has nothing to do with member rvalue references. If we had something like:
struct Wrapper {
X&& x;
};
Wrapper w{X()};
then the lifetime of the temporary X
persists through the lifetime of w
, and w.x
isn't a dangling reference. But that's because there's no function call.
†C++17 introduced a 3rd context which involves copying an array, which is unrelated here.