【问题标题】:Assignment to array in C++17C++17中的数组赋值
【发布时间】:2019-12-17 17:32:46
【问题描述】:

这里有一些代码:

int main()
{
    using T = int[3];
    T a;
    a = T{};
}

据我所知,根据 C++17 标准,这段代码是正确的,但是我尝试的每个编译器都拒绝了它。

这段代码真的不正确吗?如果是这样,该标准的哪些条款?


到目前为止我的调查:在 C 和旧版本的 C++ 中,代码不正确,因为赋值运算符的左操作数必须是可修改的左值,a 要么不是,要么没有明确说明。但是由于 C++17 a 被明确指定为可修改的左值(C++17 [basic.lval]/7)。

这里没有应用数组到指针的转换:[expr.ass] 没有明确指定它,[expr]/9 和 [expr]/10 似乎不适用:=期望一个纯右值作为右操作数,并且提供了一个纯右值。 (并且它期望一个左操作数作为左操作数,并且提供了一个左值)。如果在期望prvalue的地方提供了glvalue,则这些条款适用,反之亦然。

[expr.ass]/3 表示右表达式被隐式转换为左操作数的类型。但由于双方都有相同的类型int[3],似乎不需要转换。

所以我没有看到将 [expr.ass]/2 排除在应用之外的条款,即右侧的值存储在左侧引用的对象中。


最新的草案围绕 [basic.lval]/7 和 [expr]/9-10 中的条款移动,但似乎没有改变它们的含义,它甚至重新措辞 [expr.ass]/ 2更清楚:

在简单赋值 (=) 中,左操作数引用的对象通过将其值替换为右操作数的结果来修改。

【问题讨论】:

  • “但是由于 C++17 a 被明确指定为可修改的左值 (C++17 [basic.lval]/7)。” -- 五月您引用该相关文本以供方便参考?
  • 所以你想为你的变量分配一个未初始化的值?
  • @iammilind see here
  • @SidS T{} 将所有数组元素初始化为0

标签: c++ arrays language-lawyer c++17 variable-assignment


【解决方案1】:

据我所知,“可修改左值”的定义要么在 C++ 中未指定,要么数组被有意指定为可赋值(我怀疑前者是真的,因为没有编译器会这样做)。

标准(最新草案)说:

[basic.lval]

一个左值是可修改的,除非它的类型是 const 限定的或者是一个函数类型。

这个比较简洁,但是没有排除数组。

此外,至少自 C++03 以来,标准版本并没有改变这一点,其中指定了以下内容:

[basic.lval]

11 函数不能修改,但函数指针可以修改。

12 指向不完整类型的指针可以修改。 ...

13 const 限定表达式的所指对象不得修改 ...

除了使用更具描述性而不是确定性的措辞外,其他内容基本相同。不排除数组。


相比之下,C11 标准非常清晰(引用 N1548 草案):

6.3.2.1 左值、数组和函数指示符

1 ... 可修改的左值是没有数组类型的左值,...

【讨论】:

  • 有人可能会争辩说,实际上从未禁止对数组进行赋值,如果是这样的话,那么......(大吃一惊)
  • 据我所知,“可修改左值”的定义要么在 C++ 中未指定,要么数组被有意指定为可赋值modifiable lvalue 定义引入 C++ 标准的人将左值与对象混淆了。
【解决方案2】:

因为内置运算符也受 [over.built] 支配,即:

代表子句 [expr] 中定义的内置运算符的候选运算符函数在本小节中指定。

对于赋值运算符,对应函数的形式为:
over.built#19

对于每个三元组 (L, vq, R),其中 L 是 算术类型,R 是 提升算术类型,存在表格

对于每一对 (T, vq),其中 T 是任何类型,都存在以下形式的候选算子函数

Tvq& operator=(T vq&, T*);

对于每一对 (T, vq),其中 T 是一个枚举或指向成员类型的指针,存在以下形式的候选运算符函数

vq T& 运算符=(vq T&, T);

因此,当对应的参数为a, T{} 时,它们都不能作为候选函数。所以,程序应该是格式错误的。

【讨论】:

  • @LanguageLawyer 那可能是basic.lval#7中没有数组类型的规则,因为dcl.array#5表示数组类型的对象必须是不可修改的对象。
  • 我已删除此注释,请查看较新的草稿。 modifiable lvalue 的历史很有趣。 AFAIK Richard Smith 将左值与对象混淆,告诉数组类型的对象可以修改,这就是为什么数组类型的左值不应该从可修改的左值中排除并更改 modifiable lvalue 定义的原因。然后他在标准讨论中无辜地写道,C++ 中没有任何内容禁止分配给数组。顺便说一句,后来他告诉他,他的意思是数组在口语意义上是可修改的,而在 C++ 中,只能修改标量类型的对象。
  • @LanguageLawyer 我不认为可以修改数组类型的对象。反过来说,它的元素是可以修改的,也就是说,一个对象的子对象可以修改,并不代表这样一个完整的对象可以修改,它们是两个概念。
【解决方案3】:

C++ 标准中没有规定纯右值数组的具体化,正如您在 [class.temporary]/5 的Note 3 中看到的,它总结了这些具体化发生的情况。

【讨论】:

  • 注释不规范;第 2.1、2.3 和 2.6 点还指定了纯右值数组的一些具体化情况。案例auto&& b = T{}; 将在第 2.1 点下,具体化prvalue 数组。
  • @M.M“注释不规范”请参阅我的问题here。关于您的下一条评论,我应该说“没有规定在分配中实现数组。
  • 其中哪些子句涵盖了int c; c = int{}; 中的具体化?
  • 这并没有说明临时实现的任何内容
猜你喜欢
  • 1970-01-01
  • 2011-05-06
  • 2019-03-16
  • 2021-12-14
  • 2015-10-10
  • 2020-09-07
  • 2023-04-05
  • 1970-01-01
  • 2012-08-23
相关资源
最近更新 更多