The following code:
#include <tuple>
int main ()
{
auto f = [] () -> decltype (auto)
{
return std::get<0> (std::make_tuple (0));
};
return f ();
}
(Silently) generates code with undefined behaviour - the temporary rvalue returned by make_tuple
is propagated through the std::get<> and through the decltype(auto) onto the return type. So it ends up returning a reference to a temporary that has gone out of scope. See it here https://godbolt.org/g/X1UhSw.
Now, you could argue that my use of decltype(auto)
is at fault. But in my generic code (where the type of the tuple might be std::tuple<Foo &>
) I don't want to always make a copy. I really do want to extract the exact value or reference from the tuple.
My feeling is that this overload of std::get
is dangerous:
template< std::size_t I, class... Types >
constexpr std::tuple_element_t<I, tuple<Types...> >&&
get( tuple<Types...>&& t ) noexcept;
Whilst propagating lvalue references onto tuple elements is probably sensible, I don't think that holds for rvalue references.
I'm sure the standards committee thought this through very carefully, but can anyone explain to me why this was considered the best option?
forward_as_tuple
. You want the value category preserved. Or if you want to extract one value from a functions return value. – Aliformstd::tuple<int>
and I callstd::get<0>
on it I would expect to get a plainint
, not anint&&
. Can you give me a concrete example where you'd want something else? – Ecgget
needed for effective structured bindings? – Prefecturetuple_element
type when passed an rvalue reference tuple) seem to work fine. What am I missing? – Ecg