26

考虑这段代码(演示):

#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?)
    }

对c 数组副本的结构化绑定由 Clang声明为const ,由 GCC声明为非 const 。const

GCC 对 c 数组的行为与观察到的聚合或类元组类型的行为一致。

另一方面,从我对标准的阅读来看,我认为 Clang 遵循所写的内容。在[dcl.struct.bind]/1中, e 具有 cv A类型,其中 A 是初始化表达式的类型,而cv是结构化绑定声明的 cv 限定符。并且初始化表达式的类型ar对应于[expr.type]/1 const int[2]

应该期待什么?我的观点是 Clang 遵循标准。另一方面,我觉得其意图是数组、聚合和类似元组的类型的行为是等效的。

4

1 回答 1

19

[dcl.struct.bind]中标准的措辞说:

如果初始化程序中的赋值表达式具有数组类型并且不存在引用限定符,则具有类型cv并且每个元素都从赋值表达式的相应元素进行复制初始化或直接初始化,如初始化程序的形式所指定.Ae A

我们有auto [i,j] = ar;ar有数组类型const int[2],标准的措辞清楚地表明了e有类型const int[2]。因此,根据措辞,每个绑定都引用元素类型——即const int. Clang 在技术上是正确的。

然而,正如 Richard Smith 在gcc bug 80649中指出的那样:

我认为这是标准中的一个错误。数组类型的 cv 限定符应该被丢弃,因为它们将用于任何正常的自动推导。

这似乎是对的。当您编写时,auto x = y;您当然希望x不是顶级的const,但在这里我们仍然存在这种情况。我认为目前还没有针对此问题的核心问题,但应该存在。

于 2018-12-11T15:32:59.503 回答