在 C++17 中分配给数组

Assignment to array in C++17

本文关键字:数组 分配 C++17      更新时间:2023-10-16

下面是一些代码:

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

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

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


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

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

[expr.ass]/3 表示右表达式隐式转换为左操作数的类型。但由于双方具有相同的类型int[3]因此似乎没有必要进行转换。

因此,我没有看到任何条款可以排除 [expr.ass]/2 的应用,即右侧的值存储在左侧引用的对象中。


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

在简单赋值(=)中,左操作数所指的对象被修改为右操作数的结果,将其值替换为右操作数的结果。

据我所知,"可修改的左值"的定义要么在C++中指定不足,要么故意将数组指定为可分配(我怀疑前者是正确的,因为没有编译器做后者)。

该标准(最新草案)说:

[基本.lval]

左值是可修改的,除非其类型是常量限定的或函数类型。

这非常简洁,但没有排除数组。

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

[基本.lval]

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

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

13 常量限定表达式的指称不得修改......

这基本上是相同的,除了使用更多的描述性而不是确定性的措辞。不排除数组。


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

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

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

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

表示子句 [expr] 中定义的内置运算符的候选运算符函数在此子句中指定。

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

对于每个三元组(L,vq,R),其中L是算术类型,R是提升的算术类型,存在以下形式的候选算子函数

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

T vq&

operator=(T vq&, T*);

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

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

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

C++ 标准中没有关于 prvalue 数组具体化的规定,正如您在 [class.temporary]/5 的注释 3 中看到的那样,它总结了这些具体化发生的情况。