当我在阅读http://thbecker.net/articles/rvalue_references/section_01.html时,我得到了下面的信息.
// 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
Run Code Online (Sandbox Code Playgroud)
为什么int*p2 =&foobar(); 是错误语句,而int*p1 =&foo(); 不是错误.如果第一个是左值,那么后来的左值是多少?
提前致谢
小智 9
假设我们在C中有下面显示的示例代码.它会编译吗?左值和右值的概念如何在这个问题中起作用?
#define X 8
int main(void)
{
++X; // will this line compile?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
为了真正理解上面的代码和问题,必须对lvalues和rvalues的概念进行一些解释.在我们继续之前,你应该注意到这里提出的左值和右值的定义并不准确,因为即使C标准本身在定义上也是相当模糊的.
rvalues和lvalues之间的区别
对象是可以检查但不一定修改的内存区域.左值是一个引用这种对象的表达式.术语"左值"最初指的是出现在表达式左侧(因此"l")手侧的对象.该定义不再适用,因为任何const限定类型也被认为是左值,但它永远不会出现在赋值语句的左侧,因为它无法修改.因此,创建术语"可修改的左值"以引用可以修改的左值,并且const限定类型不属于此类别.
rvalue是具有值但不能赋值的任何表达式.也可以说rvalue是任何不是左值的表达式.右值的一个例子是文字常量 - 类似'8'或'3.14'.所以,显然上面代码中的值'8'是一个右值.
使用我们对左值和右值的理解来回答这个问题
现在让我们尝试解决问题.严格地说,前缀(或后缀)增量运算符的操作数必须是可修改的左值.那么,上面代码中前缀增量运算符的操作数是什么?
由于X是一个宏,因此在运行预处理器之后,上面的语句将扩展为"++ 8".这意味着"8"是前缀增量运算符的操作数.并且,因为8是一个rvalue,所以它不能用作"++"的参数.反过来,这意味着上面的代码将无法编译.
所以我们有两个功能:
int& foo();
int foobar();
Run Code Online (Sandbox Code Playgroud)
foo
是一个返回lvalue-reference to int的函数foobar
是一个返回int的函数函数调用表达式:
foobar()
foo()
Run Code Online (Sandbox Code Playgroud)
两者都有int类型(引用从表达式中删除,因此foo()
具有类型int
而不是lvalue-reference to int
).这两个表达式具有不同的值类别:
foobar()
是一个prvalue(函数调用返回非引用的函数是一个prvalue)foo()
是一个左值(对返回左值引用的函数的函数调用是左值)你不能取rvalue的地址(prvalue是一种rvalue),所以&foobar()
不允许.
您可以获取左值的地址,这&foo()
是允许的.
归档时间: |
|
查看次数: |
9245 次 |
最近记录: |