【问题标题】:Shall structured binding to a copy of a const c-array be const?对 const c-array 副本的结构化绑定应该是 const 吗?
【发布时间】:2019-05-12 13:28:16
【问题描述】:

考虑一下这段代码 (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-array 的副本由 Clang 声明为 const,由 GCC 声明为 non-const

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

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

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

【问题讨论】:

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


【解决方案1】:

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

如果 initializer 中的 assignment-expression 具有数组类型 A 并且不存在 ref-qualifier,则 e 具有键入 cv A 并且每个元素都从 assignment-expression 的相应元素复制初始化或直接初始化,如 initializer 的形式所指定

我们有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,但在这里我们仍然存在这种情况。我认为目前还没有针对此问题的核心问题,但应该存在。

【讨论】:

  • cv-qualification cv 来自 decl-specifier-seq ("auto") 而不是初始化器 ("ar"),不是吗?除非它说A 上的限定符被合并到cv 中。但我不明白为什么会这样。没有 ref-qualifier,为什么要保持 constness?它不会在其他任何地方这样做。
  • @LightnessRacesinOrbit 确实如此 - 但 A 是一个 const 数组,所以 cv A 仍然是一个 const 数组。我认为我们不想保持 constness,因此是核心问题。
  • 嗯,我会被说服的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-21
  • 2016-02-18
  • 1970-01-01
  • 1970-01-01
  • 2014-08-08
相关资源
最近更新 更多