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

Is this true that variables whose address can be taken are lvalues?

最近在阅读 scott meyers 的通用参考博客时,我发现 "if you can take the address of an expression, the expression is an lvalue." 但这是真的吗

假设我有以下代码

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

在上面的例子中,Test() 是临时的,即右值,我能够获取它的地址(对于 gcc,我们可以使用 -fpremissive,对于 msvc,它将直接编译)所以我们可以说它是左值并且还有 bcoz 我们可以做 Test() = Test() 但是因为我们可以对它进行右值引用所以它应该是右值。

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

你的第一个代码不正确,因为 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:

启用此类扩展

Downgrade some diagnostics about nonconformant code from errors to warnings. Thus, using -fpermissive will allow some nonconforming code to compile.

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

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

因此,这个例子证明了我们只能获取左值的地址,前提是我们使用的是标准化编译器。

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