Trying to understand working of structured bindings with const and references in particular as std::tuple is decomposed into named variables.
In the following case, it makes sense that a would be of type const int, with int& for b since int& const == int&, but how come the type of a1 isn't const int&? Is & only applied to the return object of get()?
int x;
std::tuple<int, int&> get()
{
return std::tuple<int, int&>(9, x);
}
int main()
{
const auto [a, b] = get();
const auto& [a1, b1] = get();
static_assert(std::is_same_v<const int, decltype(a)>);
static_assert(std::is_same_v<int&, decltype(b)>);
static_assert(std::is_same_v<const int, decltype(a1)>);
static_assert(std::is_same_v<int&, decltype(b1)>);
}
According to cpp-insights, that's how unpacking works. It's clear how it's const int& a1. however static_assert claims otherwise. Why the conflict? How else would the return from get() be decomposed?
const std::tuple<int, int &> __get12 = get();
const int && a = std::get<0UL>(static_cast<const std::tuple<int, int &> &&>(__get12));
int & b = std::get<1UL>(static_cast<const std::tuple<int, int &> &&>(__get12));
const std::tuple<int, int &> & __get13 = get();
const int & a1 = std::get<0UL>(__get13);
int & b1 = std::get<1UL>(__get13);
In simple terms, that's how I imagined would happen but it doesn't seem like it:
const auto& t = get();
const int& a1 = std::get<0>(t);
int& b1= std::get<1>(t);
EDIT:
The following works then that means structured binding does indeed not discard references, and perhaps it's just what decltype does as it returns the type of the element only not including the reference?
std::tuple<int> tx = std::make_tuple(42);
auto& [xz] = tx;
decltype(xz) yz = 0; // int& yz = 0;
static_assert(std::is_same_v<int, decltype(yz)>);
xz = 31; // tx<0> => 31
Structured bindings are not regular variables and are treated differently by
decltype. The output of cppinsights is only a close approximation. cppreference says:The reference qualifier (
&) does apply to the intermediary object (named__get31in your question).Conceptually, it helps to compare with a struct used in this way:
In that case, even though
decltype(value)istup &,decltype(value.a)isint, just like the structured bindinga1of astd::tuple<int, int&> &has adecltypeofint.