10

为什么C++(11) 中没有 Rconst int我认为 R 值是不能在左侧的“任何东西”,而常量可以满足这一点。此代码失败:

int f(int && x) { return 100; }

void g() {
  const int x = 1;
  f(x);
}

error: invalid initialization of reference of type ‘int&&’ from expression
of type ‘const int’
4

4 回答 4

12

好的,表达式1分为三类:

  1. 那些代表具有身份且无法移动的对象;
  2. 那些代表具有身份且可以从中移动的对象;
  3. 那些表示没有身份且可以从中移动的对象;

第一个被称为左值,第二个是xvalues,第三个是prvalues。如果我们将左值和 xvalues 放在一起,我们就有了 glvalues。Glvalues 是所有表示具有标识的对象的表达式。如果我们将 xvalues 和 prvalues 放在一起,我们就有 rvalues。右值是表示可以移动的对象的所有表达式。

有问题的表达式x, 是一个glvalue:可以写&x,所以对象显然有一个标识。

我们可以从这个表达式中移开吗?这个对象即将过期吗?不它不是。它仅在当前表达式之后的某个时间过期。这意味着它不能被移动。这使它成为一个左值。

所有这些名称可能有点令人困惑,因为 C++ 中的左值和右值不再意味着它们在 C 起源中的含义。C++ 的含义与在 assignment 2的左侧或右侧完全无关。

就个人而言,我更喜欢使用Bjarne这篇论文中的术语:iM-values(而不是 lvalues)、im-values(而不是 xvalues)、Im-values(而不是 prvalues)、i-values(而不是 glvalues)、和 m 值(而不是右值)。不幸的是,这不是标准使用的术语。


1这里的“有身份”是指“可以取其地址”;“可以移出”意味着它即将到期,要么是由于它的临时性质,要么是因为程序员通过调用std::move或类似的东西在类型系统中明确表示了这一点。

2你可以在赋值的左边有右值:std::vector<int>(17) = std::vector<int>(42)是一个有效的表达式,即使它是无用的。

于 2012-12-05T13:58:59.770 回答
6

我认为 R 值是“任何东西”,不能在 [赋值操作] 的左侧

那是 C++03 的定义rvalue,即便如此,它也是一种俗语,并非普遍适用。

在 C++11 中, 和 的定义lvalue有所rvalue改变。规则很复杂,标准中的个别情况会根据具体情况进行处理,但这里有一个一般的经验法则:

  1. 如果您可以获取某物的地址,那么它就是lvalue
  2. 如果表达式的类型是lvalue引用,则该表达式是lvalue
  3. 如果以上都不适用,那就是rvalue

在您的特定情况下,您可以获取x(例如,它“有名字”)的地址,因此它是一个左值。

您可以在两篇优秀的文章中阅读更多关于 C++11 中左值和右值的信息:

于 2012-12-05T14:04:36.963 回答
1

参数类型是右值引用,标准禁止使用“引用相关”类型的左值初始化右值引用。

8.5.3 参考文献[dcl.init.ref]

...

5 ... 如果 T1 与 T2 引用相关并且引用是右值引用,则初始化表达式不应是左值。

因此,以下是错误:

void f (long &&);

const long x = 1;
void g () { f (x); }

但以下不是:

void f (long &&);

const int x = 1;
void g () { f (x); }

因此,错误的原因不仅仅是“初始化不是使用右值”,而是因为“初始化是使用与引用相关类型的左值”。

于 2012-12-05T13:56:13.787 回答
0

简单来说,您应该能够“窃取”右值的值。这是对右值进行不同处理的重点。所以右值应该是未命名的,即将在不久的将来死去的东西。

于 2012-12-05T14:01:46.403 回答