为啥 int foo() 是一个右值,而 int& foo() 在这个例子中是一个左值?

Posted

技术标签:

【中文标题】为啥 int foo() 是一个右值,而 int& foo() 在这个例子中是一个左值?【英文标题】:Why is int foo() an rvalue, while int& foo() is an lvalue in this example?为什么 int foo() 是一个右值,而 int& foo() 在这个例子中是一个左值? 【发布时间】:2019-08-26 08:41:31 【问题描述】:

我们有以下代码示例:

// lvalues:
  //
  int i = 42;
  i = 43; // ok, i is an lvalue
  int* p = &i; // ok, i is an lvalue
  int& foo();
  foo() = 42; // ok, foo() is an lvalue
  int* p1 = &foo(); // ok, foo() is an lvalue

// rvalues:
  //
  int foobar();
  int j = 0;
  j = foobar(); // ok, foobar() is an rvalue
  int* p2 = &foobar(); // error, cannot take the address of an rvalue
  j = 42; // ok, 42 is an rvalue

我试图理解为什么一个普通的函数定义是这样的:

int foobar();

应该是一个右值,虽然是同一个函数,但返回类型是对象引用,如下所示:

int& foobar();

是一个左值。 (第二部分很自然,因为我们在定义函数时特别要求并因此保留引用。但是,第一个示例对我来说很难掌握,因为我期望函数的内存位置以某种方式隐式扣除,基于这样的假设——这可能是错误的——每个函数在内存中都有自己的、不可更改的位置,总之,第一个示例也应该是一个左值引用)。请先试着解释一下这方面。

我明白了:

左值是一个引用内存位置的表达式,它允许我们通过 & 运算符获取该内存位置的地址。右值是不是左值的表达式。

但是,如上所述,我最感兴趣的是如何根据左值/右值概念处理函数,而不是简单对象或与之相关的函数。

谢谢!

【问题讨论】:

你误解了错误:不是函数是右值,而是它返回的东西。 @freakish 能否请您扩展一下这个主题? 见博洛夫的回答。 【参考方案1】:

foobar() 不是函数。这是一个函数调用。它的评估是调用函数的结果,即int,它是一个右值。

下面是你如何将函数分配给一个引用(这是一个比获取它的地址更好的测试):

int (&a)() = foo; // OK
int (&&b)() = foo; // OK

这是分配函数地址的方式

int (*a)() = &foo; // OK

我理解:“左值是一个引用内存位置的表达式,它允许我们通过 & 运算符获取该内存位置的地址。右值是一个不是左值的表达式。”

嗯...这是一个非常简单的定义。如果您对该主题感兴趣,这里有一些链接:

What are rvalues, lvalues, xvalues, glvalues, and prvalues?

Value categories

【讨论】:

以上是关于为啥 int foo() 是一个右值,而 int& foo() 在这个例子中是一个左值?的主要内容,如果未能解决你的问题,请参考以下文章

c++:函数左值或右值

三元运算符为啥以及何时返回左值?

右值引用,移动语义,完美转发

为啥这个函数返回垃圾值

在带有模板的结构中,为啥左值会推导出为右值?

C++ 11 右值引用以及std::move