It's only ever problematic in the case where the initializer is a function call that returns a short-lived rvalue reference. With less words and more code:
// Fine; lifetime extension applies!
auto&& ref = 42;
auto id = [](int&& i) -> int&& { return std::move(i); };
auto&& uhoh = id(42);
// uhoh is now a stale reference; can't touch it!
In contrast, auto uhoh = id(42);
would have worked fine.
In your case, because std::make_tuple
returns a value and not an rvalue reference there is no problem.
I'm of the opinion that the real danger is from those functions and function templates with rvalue reference parameters and that return an rvalue reference to either those of some subobjects which lifetimes depend on those. (That being said, something as simple as auto&& ref = std::move(42);
exhibits the problem!)
The situation is not entirely new from C++11, consider: T const& ref = bar(T_factory());
.
auto&& var = func()
, #13619006 – Helmanconst int & foo() { return 42; } int i = foo();
andint foo() { return 42; } const int & i = foo();
are the same situations (they are not). – Hundredpercenter