提问人:Jan Schultke 提问时间:9/6/2023 最后编辑:Jan Schultke 更新时间:9/9/2023 访问量:372
您可以取消引用临时数组吗?
Can you dereference a temporary array?
问:
请考虑以下代码:
void foo() {
int arr[1];
*arr; // OK
using T = int[1];
*T{}; // OK for Clang and MSVC
// GCC error: taking address of temporary array
}
我的直觉是,这应该会导致数组到指针的转换,并且间接格式良好。
但是,我对此并不完全确定。*T{}
GCC 是对的,还是这是一个错误?这是故意的,以防止开发人员犯错误吗?毕竟,您通常不会取消引用数组。这在任何地方都有记录吗?
免責聲明 |
---|
CWG 第 2548 期已确认“通过数组 prvalue 进行间接操作在今天也无效”。@StoryTeller 的答案是错误的,并且错误地理解了目标类型的含义,假设这也适用于 ,但此表达式不是指针的初始化。*T{} |
更多讨论见编辑问题 EDIT 6555
答:
在我看来,它似乎定义得很好,Clang 和 MSVC 会根据需要进行定义。
[expr.unary.op](强调我的)
1 一元运算符执行间接操作:应用它的表达式应是指向对象类型的指针,或指向函数类型的指针,结果是引用表达式指向的对象或函数的左值。
*
然后我们有这句话告诉我们何时何地可以应用标准转换序列:
[转换总则]
1 标准转换是具有内在含义的隐式转换。[conv] 枚举了此类转换的完整集合。标准转换序列是按以下顺序排列的标准转换序列:
- 从以下集合中进行零次或一次转换:左值到右值的转换、数组到指针的转换和函数到指针的转换。
...
如有必要,将对表达式应用标准转换序列,以将其转换为所需的目标类型。
这告诉我们,可以应用标准转换序列将操作数转换为表达式所需的类型。这就是它的工作方式,因此我们只需要检查数组到指针的转换是否可以应用于我们的 prvalue 数组。*arr
[转换数组]
1 “N T 数组”或“T 未知边界数组”类型的左值或右值可以转换为“指向 T 的指针”类型的 prvalue。应用临时物化转换 ([conv.rval])。结果是指向数组的第一个元素的指针。
它可以,因为标准甚至明确要求一个临时数组具体化,并且指针指向它的第一个元素。总而言之,GCC 拒绝有效的代码,所以可以说它有一个错误。
评论
GCC 是正确的,因为间接只能应用于指针。[expr.unary.op]/1:
一元运算符执行间接操作:应用它的表达式应是指向对象类型的指针,或指向函数类型的指针,结果 [...]
*
注: CWG 1642 和 EDIT 3945 将间接应用于 prvalue 操作数。
*arr
是可以的,因为是一个左值,并且 [basic.lval]/6:arr
每当 glvalue 显示为需要该操作数的 prvalue 的运算符的操作数时,就会应用左值到右值、数组到指针或函数到指针的标准转换来将表达式转换为 prvalue。
数组到指针的转换 ([conv.array]) 应用于。arr
T{}
已经是 prvalue(数组类型),并且这里没有需要数组到指针转换的措辞,所以不行。*T{}
评论
[]
T
T
using T = int(&&)[1]; *T{};
评论
(T{})[0];
工程。为什么 gcc 抱怨取地址?运营商是否正在获取地址?奇怪。*
T{}[0]
*(T{} + 0)
*T{}
由于类似 MVP 的行为,编译器将其误认为是复合文字的空情况,这是一种 C 结构,但不是合法的 C++。复合文字可能作为 C++ 编译器中的扩展存在,这就是 Clang 和 MSVC 可能正在做的事情,或者他们正确地将其识别为不是这样。T{}
T = int