左右值和左右值引用是有区别的。
左右值是指对变量类别的区分,左值是有地址的值,可以长期存在;而右值是将亡值,是临时量,没有名字。
而左右值引用是指变量的类型,如int&, int&&等,下面举一个例子:
void func(int &p) { cout << "&p" << endl; return; } void func(int &&p) { cout << "&&p" << endl; return; } int main() { int k = 1; int &lr = k; int &&rr = move(k); func(k); func(lr); func(rr); func(forward<int>(rr)); func(1); return 0; }
vs2022输出如下:
这里k被编译器推导为int &类型。至于rr的输出是&p,需注意区分左右值和左右值引用的关系。
此处rr是一个变量类型为int的右值引用的左值,因此rr作为参数和左值参数匹配。
至于后两个输出具体见下文分析。
上例中也可以看出,当函数参数类型为左值引用时,匹配左值参数,右值引用匹配右值参数。
这里可以再提一下引用折叠和万能引用的内容。
补充知识:
万能引用即模板中T&&或auto &&,必须注意当且仅当存在类型推导时&&才会被认为是万能引用。
左值和右值在模板推导时是存在差异的,对于类型T的lvalue(左值),模板会推导为T&类型;但是对于类型T的右值,模板会推导为T。
在模板函数中,模板参数类型由编译器去自动匹配时,左值会匹配为t&,右值会匹配为t&&
using namespace std; template<typename T> void print(T& value) { cout << "左值" << endl; } template<typename T> void print(T&& value) { cout << "右值" << endl; } template<typename T> void func(T&& value) { print(value); print(forward<T>(value)); } int main() { int k = 1; int &lr = k; int &&rr = move(k); cout << "k" << endl; func(k); cout << "lr" << endl; func(lr); cout << "rr" << endl; func(rr); cout << "1" << endl; func(1); return 0; }
vs2022输出如下:
这里逐一分析一下。对于前三者k,lr,rr,他们三者均为左值,因此编译器会推导出其类型为int &,从而T的类型为int &。
函数func的参数类型为T &&。&&之所以被称为万能引用,是因为引用折叠的原理。
对于前三者k,lr,rr,T=int &,T &&=int & &&=int &。因此该处函数参数为左值引用,而传入参数又为左值,故匹配,func可被正常调用。
对于常数1,其是右值,T=int。(这里需注意万能引用绑定到右值模板会推导为T而非T&&),因此T&&=int &&,(注意此处未发生引用折叠)。因此参数类型为int&&可正常匹配右值1.
所以说左右值都可以匹配函数func,故而称模板参数T&&为万能引用。
再看程序输出,k,lr,rr均为左值,到函数内部也是左值,因此输出均为左值。
1是右值,匹配到函数内,参数value获取了该右值,但是对于value来说,其是一个类型为右值引用的左值,因此直接将其作为print的参数会输出左值。
但是使用forward函数转发,forward函数会根据参数类型决定返回值类型,若参数为右值或右值引用,则会返回右值,反正返回左值,因此得到的返回值是右值。
本文为个人理解,仅供参考,若有错误欢迎指出
标签:rr,右值,int,左值,c++,函数参数,引用,&& From: https://www.cnblogs.com/Explosion556/p/17461760.html