这是真的,可以采用地址的变量是左值吗?

时间:2016-05-18 09:00:14

标签: c++ reference lvalue rvalue

最近在阅读scott meyers关于通用引用的博客时,我发现声明“如果你可以获取表达式的地址,那么表达式就是左值”。但这是真的吗

假设我有以下代码

class Test
{
};
int main()
{
   std::cout << "Address is " << &(Test()) << std::endl;
   Test() = Test();
   Test&& t = Test();
   return 0;
}

在上面的情况下,Test()是临时的,即rvalue,我能够获取该地址(使用gcc我们可以使用-fpremissive和msvc它将直接编译)所以我们可以说这是lvalue而且bcoz我们可以做Test()= Test()但是因为我们可以对它进行右值引用,所以它应该是rvalue。

那么为什么我们总是说如果我们可以获取变量的地址那么它是左值?

2 个答案:

答案 0 :(得分:3)

您的第一个代码不正确,因为z的声明应为int*,此代码编译并正常运行:

int x = 12;  // x is lvalue
int& y = x;  // y is lvalue reference
int *z = &y; // can take address of lvalue reference (address of the referenced)
assert(z == &x);

对于您的第二个示例,Test()实际上是prvalue,您无法按照标准提及的方式获取其地址。

MSVC的扩展程序允许您获取prvalue的地址,而GCC允许您使用-fpermissive启用此类扩展程序:

  

将有关不合规代码的一些诊断程序从错误降级为警告。因此,使用-fpermissive将允许编译一些不合格的代码

这意味着Scott Meyers是对的,编译器是错误的,至少在符合标准的问题上。另外,通过传递-fpermissive你告诉gcc不那么严格,即允许你的不符合代码编译。为了完全符合要求,您应该始终使用-pedantic-pedantic-errors进行编译(因为就像MSVC一样,gcc默认情况下也会启用一些语言扩展)。

答案 1 :(得分:0)

根据holt的评论,因为我编辑了这个问题所以我认为正确的答案应该是上面的上下文中的Test()是rvalue,如果我们使用标准化的编译器,这个代码将不会编译,所以如果你的代码编译它意味着要么在gcc中设置fpermissive标志,要么使用msvc设置你的设置允许你使用它。 第二行Test()= Test()正在工作,因为它等同于Test()。operator =(),我们可以从rvalue调用函数。 现在第三行是隐式的,因为它是一个右值,所以我们可以对它进行右值引用。

因此,通过这个例子证明,只要我们使用标准化编译器,我们就只能获取左值的地址。

这个问题的所有功劳都应该归功于我刚刚写的答案,因为人们通常不会阅读评论,而且bcoz我已经编辑了这个问题