C++ 右值和左值之间的精确差
当我在读书的时候,我得到了如下的嘲笑C++ 右值和左值之间的精确差,c++,c++11,rvalue,C++,C++11,Rvalue,当我在读书的时候,我得到了如下的嘲笑 // lvalues: // int i = 42; i = 43; // 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() i
// lvalues:
//
int i = 42;
i = 43; // 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*p2=&foobar();是错误语句,而int*p1=&foo();这不是一个错误。后一个是左值,而前一个是右值
提前感谢因此我们有两个功能:
int& foo();
int foobar();
是一个将左值引用返回int的函数foo
是一个返回int的函数foobar
foobar()
foo()
两者都具有int类型(引用从表达式中删除,因此foo()
具有int类型int
,而不是对int的左值引用)。这两个表达式具有不同的值类别:
foobar()
是prvalue(对返回非引用的函数的函数调用是prvalue)
foo()
是左值(对返回左值引用的函数的函数调用是左值)
不能获取右值的地址(prvalue是右值的一种),因此不允许使用&foobar()
您可以获取左值的地址,这样就允许使用&foo()
。假设我们有下面用C显示的示例代码。它会编译吗?左值和右值的概念在这个问题中是如何工作的
#define X 8
int main(void)
{
++X; // will this line compile?
return 0;
}
必须稍微解释一下左值和右值的概念,以便真正理解上面的代码以及所问的问题。在我们继续之前,您应该注意到这里给出的左值和右值的定义并不准确,因为即使是C标准本身在定义上也相当模糊
右值和左值之间的差异
对象是可以检查但不一定要修改的内存区域。左值是指此类对象的表达式。术语左值最初指出现在表达式左侧(因此为“l”)的对象。该定义不再适用,因为任何常量限定类型也被视为左值,但它永远不会出现在赋值语句的左侧,因为它无法修改。因此,术语“可修改的左值”是指可以修改的左值,常量限定类型不属于这一类
右值是任何具有值但不能指定值的表达式。也可以说右值是任何不是左值的表达式。右值的一个例子是一个文字常量,类似于“8”或“3.14”。显然,上面代码中的值“8”是一个右值
用我们对左值和右值的理解来回答这个问题
现在让我们试着解决这个问题。严格来说,前缀(或后缀)增量运算符的操作数必须是可修改的左值。那么,在上面的代码中,前缀增量运算符的操作数是多少
由于X是一个宏,在预处理器运行后,上面的语句将扩展到“++8”。这意味着“8”是前缀递增运算符的操作数。而且,由于8是右值,因此不能将其用作“++”的参数。这反过来意味着上面的代码将无法编译。我相信你的最后一句话已经倒转了为什么不可能取foo的地址?@ss7don:你是说表达式foo()
?你可以取foo()的地址
。再次阅读我答案的最后一行。我接受了这个答案,因为它看起来合理。坦率地说,我仍然不理解foo和foobar之间的确切区别。两者都是函数。但是一个是右值,另一个是左值。@ss7don:值类别是表达式的属性,而不是函数的属性。值类别函数调用表达式的返回类型根据其返回类型计算。函数foo的返回类型为int&
。函数foobar的返回类型仅为int
。引用&
的存在与否决定了对该函数的函数调用的值类别。谢谢。现在请tween值和函数消除了我的疑问。很好,但为什么要用这个例子呢?我不知道这样的问答题如何有助于理解这个问题。