【问题标题】:Are lvalues really non-temporary objects?左值真的是非临时对象吗?
【发布时间】:2015-08-17 15:59:38
【问题描述】:

虽然不是实际标准,但我依赖 cppreference.com 上的 this page 来了解这个特定的措辞:

左值是标识非临时对象或 非成员函数。

以下表达式是左值:

  • 范围内的变量或函数的名称,与类型无关,例如 std::cin 或 std::endl。即使变量的类型是右值 引用,由其名称组成的表达式是一个左值 表达。

...

我对上面引用部分的(简化)理解是左值:

  1. 是参考
  2. 不能是临时对象

我知道引用不是对象,所以第 2 点必须意味着就引用而言,它不能 引用 到临时对象。但是,从表达式本身来看,这是否意味着对临时的引用不是左值?您可以引用临时非临时对象:

int myvar = 0;
int& ref_myvar = myvar; // Reference to non-temporary

class foo {};
foo const& ref_foo = foo{}; // Reference to temporary

在上面的代码sn-p中,以后在单独的表达式中使用ref_foo是不是左值?右值引用有一条规则,即在表达式中按名称使用的右值引用仍然是左值(因为此时您引用了名称)。此规则是否也适用于左值引用(因为它们也有名称,并且在表达式中使用名称本身会使其成为左值,就像右值引用变量一样)?

我希望我有某种意义。至少我希望我的困惑的根源是显而易见的。上面的左值引用如何在表达式中使用以证明与我的问题相关的一些点的一些示例也将是一个巨大的帮助。

【问题讨论】:

  • 左值不一定是引用,因为引用是类型的一部分,与值类别正交。在您的示例中,myvarref_myvarref_foo 在用作表达式时都是左值。 foo{}0 不是左值。
  • 我写了一个相关问题的答案here,也许会有所帮助。

标签: c++ c++11


【解决方案1】:

我想说 cppreference 措辞对于“一般介绍”级别的讨论甚至“大多数日常使用”级别的讨论都是可以的。但是,一旦您深入了解精细的技术细节,此类陈述可能会产生一定的误导性。

重要的一点是值类别(“作为左值”)是表达式的属性,不是对象的属性。你可以有一个临时对象通过左值访问,您可以通过右值访问非临时对象。

参考你的例子:

ref_myvarref_foo 都是左值,并且永远都是左值,无论你如何使用它们。如下:

foo&& rref = foo{};

rref 也是并且永远是左值。它是对右值的引用,但引用本身有名称,左值也是。

如果要将左值视为右值,请使用标准提供的大小写运算符:

rvalue = std::move(lvalue);

让我们分析一下这段代码:

int someint = std::move(ref_myvar);

ref_myvar 是一个左值。 std::move(ref_myvar) 是一个右值。 someint 是一个左值。


我认为没有完全标准化的定义左值的简洁方法,但 name(或不存在)在大多数定义中起着重要作用。我会尝试这样的定义;这些是左值:

  • 作为名称的表达式,枚举数和成员函数除外。
  • “对某物的左值引用”类型的表达式。
  • 取消引用指针的结果。

请注意,ref_myvarref_foorref 都是左值,因为它们都有名称。 std::move(ref_myvar) 没有名字,所以它是一个右值。

【讨论】:

  • 为了更加挑剔,我想说rref 是一个左值之后 foo&& rref = foo {};,但不是in 那句话。在声明中,它是一个声明符,而不是一个表达式。这也与声明符rref 具有“对foo 的右值引用”类型的区别有关,但表达式rref(如果出现)是类型为foo 的左值。
  • @aschepler 是的,我的意思是“使用时”,而不是“在声明中”。
  • @aschepler 你是说对于声明,赋值的左边部分不是表达式的一部分吗?我怎样才能正确理解?
  • @void.pointer 声明不是表达式(当然也不是赋值),它是一个语句。初始化器(如果有)是一个表达式。
  • @void.pointer 差不多。另外,不要忘记 rvaluexvalue 不是同级项。最低层(互斥)是 lvalue、 xvalue、prvalue。 在它们之上,有 rvalue (xvalue 或 prvalue)和 glvaluelvaluexvalue)。在这两个之上,它只是 value。 所以如果一个函数返回一个左值引用,它返回一个左值。如果它返回一个右值引用或一个非引用,它返回一个右值(分别是一个 xvalue 或一个 prvalue)。
猜你喜欢
  • 2014-10-13
  • 2019-02-28
  • 1970-01-01
  • 1970-01-01
  • 2019-12-21
  • 2019-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多