将结构化绑定到const c数组的副本的方式是否为const?

时间:2018-12-11 14:21:47

标签: c++ language-lawyer c++17 structured-bindings

考虑以下代码(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遵循标准。另一方面,我的意图是数组,聚合和类似元组的类型的行为是等效的。

1 个答案:

答案 0 :(得分:19)

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

  

如果初始化器中的赋值表达式具有数组类型A,并且没有 ref限定符,则{{ 1}}的类型为 cv e,并且每个元素都由 assignment-expression 的相应元素进行复制初始化或直接初始化,如格式所示初始化器的名称。

我们有Aauto [i,j] = ar;的数组类型为ar,该标准的措辞清楚地表明const int[2]的类型为e。因此,按照措辞,每个绑定都引用元素类型-即const int[2]。 lang在技术上是正确的。

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

  

我认为这是标准中的错误。数组类型的cv限定词应该被丢弃,就像任何正常的自动推论一样。

那似乎是对的。当您编写const int时,您肯定会希望auto x = y;不是顶级x,但在这里我们仍然会遇到这种情况。我认为目前尚无核心问题,但应该存在。