C++ 临时对象的字段是右值吗?
此代码在Clang 3.8、GCC 6.3和VS2013下编译成功,但在Clang 4.0下编译失败:C++ 临时对象的字段是右值吗?,c++,C++,此代码在Clang 3.8、GCC 6.3和VS2013下编译成功,但在Clang 4.0下编译失败: struct Foo { int x[2]; Foo() { x[0] = 3; // line A: works fine - we can assign to x[0] *&x[0] = 4; // line B: works fine - we can take the address of x[0] } }; int main() { Foo(
struct Foo {
int x[2];
Foo() {
x[0] = 3; // line A: works fine - we can assign to x[0]
*&x[0] = 4; // line B: works fine - we can take the address of x[0]
}
};
int main() {
Foo().x[0] = 5; // line C: error: expression is not assignable
*(Foo().x + 0) = 6; // line D: works fine
}
哪个编译器是正确的?Foo().x[0]
是右值还是左值
第A行和第B行在所有编译器上都工作,x[0]
肯定是一个左值,而第A行和第B行肯定引用了与第C行相同的x
,因此看起来像Foo()。x[0]
应该是一个左值。但是当以这种方式访问时,Foo()
的右值可能会传播到它的所有字段
也考虑行D,它适用于所有编译器。我认为
bar[n]
基本上只是*(bar+n)
(对于数组)的语法糖,所以D行正常工作而C行失败似乎很奇怪。Foo().x[0]
在C++11中是一个左值。在C++11中,内置下标运算符的结果始终是左值,因为它涉及取消对指针的引用
在C++14中,内置下标运算符的行为发生了更改:
- 如果
是左值,那么a
是左值a[i]
- 否则,
是一个x值a[i]
Foo()
是一个prvalue,因此访问非静态成员会产生一个xvalue。由于Foo.x
是一个xvalue,Foo.x[0]
也是一个xvalue,无法分配给它。您不应该试图修改匿名临时值。此外,如果这样的代码真的运行了,它又有什么意义呢?这只是一个玩具示例。我真正的代码类似于glUniformMatrix4fv(&Matrix::MakeOrthographic(1,2,3,4).values[0])代码>如果这有意义的话。在我更新Android NDK之前,这段代码一直运行良好,它使用了新版本的Clang,现在给出了“不能获取'float'类型的右值的地址”。所以我把它归结为我所能想到的问题的最简单表达式。@JohnZwinck:例如,临时的析构函数做了一些有趣的事情。来吧int main(){File(“filename”).data=“abc”}
猜猜文件的析构函数做什么。你的例子不是最好的。@ CONIO:你的例子不是野外看到的“真正的C++代码的典型”。“调用一种方法,比如<代码>())/代码>是允许的。@好奇你不是在调用内置的<代码> [C]>运算符,而是重载<代码> >代码>操作符<代码> STD::数组< /C> >,这不是REF限定的,因此它总是返回左值。@这是个好问题。向量和字符串也没有ref限定的下标运算符。这可能是一种疏忽,也可能是为了避免违反规则,即c[i]
与*(c.begin()+i)
相同。值得问一个新问题。@quitious@quitious只需比较C++11和C++14中的[expr.sub]standards@Curious我跟踪堆栈溢出。如果你在这里花了足够的时间,忽略QT和作业分配的所有问题,你就会意识到C++的大部分微妙之处。