I'm learning about structured binding declarations. My understanding was that in auto& [x, y] = expr;
variables x
and y
are introduced of types "reference to std::tuple_element<i, E>::type
" (for i=0, 1
and E
is the type of the invisible variable e
). Moreover, these variables are initialized with get<i>(e)
.
So, if I use auto&
and get<>
returns a value (not a reference), it should not compile, as you cannot bind an lvalue to a temporary. However, the following example builds for me in some versions of GCC, Clang, and Visual Studio:
#include <cstddef>
#include <tuple>
#include <type_traits>
struct Foo {
template<std::size_t i>
int get() { return 123; }
};
namespace std {
template<> struct tuple_size<Foo> : integral_constant<size_t, 1> {};
template<std::size_t i> struct tuple_element<i, Foo> { using type = int; };
}
int main() {
Foo f;
auto& [x] = f;
x++;
}
Moreover, C++ Insights clearly shows that clang expands the structured binding to:
Foo f = Foo();
Foo & __f17 = f;
std::tuple_element<0, Foo>::type x = __f17.get<0>();
x++;
Here, it declares x
not as a reference, but as a value. Why is that?
I expected lvalue references and compilation error: e
(__f17
in the example above) is an lvalue reference.