I have a structure
template <typename T> struct Demo { T x; T y; };
and I'm trying to write a generic function similar to std::get for tuples that takes a compile-time index I and returns an lvalue reference to the I th member of the structure if it is called with an lvalue DemoStruct<T> and a rvalue reference to the I th member of the structure if it is called with rvalue DemoStruct<T> .
My current implementation looks like
template <size_t I, typename T> constexpr decltype(auto) struct_get(T&& val) { auto&& [a, b] = std::forward<T>(val); if constexpr (I == 0) { return std::forward<decltype(a)>(a); } else { return std::forward<decltype(b)>(b); } }
However, this does not do what I expected, and always returns an rvalue reference to T
Here is a wandbox that shows the problem.
What is the correct way to return references to structure elements that preserve the category of structure values ββpassed to the function?
EDIT: As Keenan Al Sarmini noted, auto&& [a, b] = ... really infers the types for a and b as non-basic types. This is true for std::tuple , for example. and
std::tuple my_tuple{std::string{"foo"}, std::string{"bar"}}; auto&& [a, b] = my_tuple; static_assert(!std::is_reference_v<decltype(a)>);
and
std::tuple my_tuple{std::string{"foo"}, std::string{"bar"}}; auto&& [a, b] = std::move(my_tuple); static_assert(!std::is_reference_v<decltype(a)>);
compile fine even if std::get<0>(my_tuple) returns links as shown
std::tuple my_tuple{3, 4}; static_assert(std::is_lvalue_reference_v<decltype(std::get<0>(my_tuple))>); static_assert(std::is_rvalue_reference_v<decltype(std::get<0>(std::move(my_tuple)))>);
Is this a language flaw, intended, or a bug in both GCC and Clang?
c ++ language-lawyer perfect-forwarding c ++ 17 structured-bindings
Corristo
source share