Consider this code (demo):
#include <tuple>
#include <type_traits>
struct Ag{int i;int j;};
using T = std::tuple<int,int>;
using Ar = int[2];
const Ag ag {};
const T t {};
const Ar ar {};
void bind_ag(){
auto [i,j] = ag;
static_assert(std::is_same_v<decltype((i)),int&>);
}
void bind_t(){
auto [i,j] = t;
static_assert(std::is_same_v<decltype((i)),int&>);
}
void bind_ar(){
auto [i,j] = ar;
static_assert(std::is_same_v<decltype((i)),int&>); //For GCC
static_assert(std::is_same_v<decltype((i)),const int&>); //For Clang (and standard?)
}
A structured binding to a copy of a const
c-array are declared const by Clang and non-const by GCC.
The behavior of GCC for c-array is consistent with the behavior observed for aggregate or tuple-like types.
On the other hand from my reading of the standard, I suppose Clang follows what is written. In [dcl.struct.bind]/1 e has type cv A where A is the type of the initializer expression and the cv is the cv-qualifier of the structured binding declaration. And the type of the initializer expression ar
is accordingly to [expr.type]/1 const int[2]
.
What should be expected? My opinion is that Clang follows the standard. On the other hand I feel the intent was that the behaviors for array, aggregate and tuple-like types were equivalent.