考虑以下代码(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?)
}
与const
c数组副本的结构绑定由Clang声明为 const ,由 non-const 声明海湾合作委员会。
c数组的GCC行为与聚合或元组类型的行为一致。
从另一方面看,我认为Clang遵循所写的内容。在[dcl.struct.bind]/1中, e的类型为cv A ,其中A是初始化表达式的类型,而 cv 是结构化绑定声明的cv限定词。初始化程序表达式ar
的类型对应于[expr.type]/1 const int[2]
。
应该期待什么?我的观点是Clang遵循标准。另一方面,我的意图是数组,聚合和类似元组的类型的行为是等效的。
答案 0 :(得分:19)
[dcl.struct.bind]中标准的措辞如下:
如果初始化器中的赋值表达式具有数组类型
A
,并且没有 ref限定符,则{{ 1}}的类型为 cve
,并且每个元素都由 assignment-expression 的相应元素进行复制初始化或直接初始化,如格式所示初始化器的名称。
我们有A
,auto [i,j] = ar;
的数组类型为ar
,该标准的措辞清楚地表明const int[2]
的类型为e
。因此,按照措辞,每个绑定都引用元素类型-即const int[2]
。 lang在技术上是正确的。
但是,正如Richard Smith在gcc bug 80649中指出的那样:
我认为这是标准中的错误。数组类型的cv限定词应该被丢弃,就像任何正常的自动推论一样。
那似乎是对的。当您编写const int
时,您肯定会希望auto x = y;
不是顶级x
,但在这里我们仍然会遇到这种情况。我认为目前尚无核心问题,但应该存在。