1. 何為左值?何為右值?
簡(jiǎn)單的說(shuō),左值可以放在等號(hào)的左邊,右值可以放在等號(hào)的右邊。
左值可以取地址,右值不能取地址。
1.1 左值舉例:
- 變量、函數(shù)或數(shù)據(jù)成員
- 返回左值引用的表達(dá)式 如 ++x、x = 1、cout << ' '? int x = 0
1.2 右值舉例:
- 返回非引用類(lèi)型的表達(dá)式
如 x++、x + 1 - 除字符串字面量之外的字面量如 42、true
將亡值(xvalue)
- 隱式或顯式調(diào)用函數(shù)的結(jié)果,該函數(shù)的返回類(lèi)型是對(duì)所返回對(duì)象類(lèi)型的右值引用
#include<string>
#include<iostream>
using namespace std;
void print(string& str)
{
cout << "left val: " <<str << endl << endl;
}
void print(string&& str)
{
cout << "right val: " << str <<endl << endl;
}
void print(int&& i)
{
cout << "right val: " <<i << endl << endl;
}
void print(int& i)
{
cout << "left val: " <<i << endl << endl;
}
int getVal(){
return 666;
}
int main(int argc, char *argv[])
{
string str1 = "hello 1";
print(str1);
print("hello 2");
print(move(str1));
int ab = 88;
print(ab);
print(++ab);
print(ab++);
print(getVal());
//string& aa = "abc"; // 編譯不過(guò),左值引用不可以賦右值
const string& bb = "abc"; // 常量左值引用可以賦右值
return 0;
}
輸出:
?1.3 左值引用與右值引用
?
規(guī)則簡(jiǎn)化如下:
左值引用 {左值}
右值引用 {右值}
常左值引用 {右值}
string f()
{
return "bbb";
}
int main()
{
string &s1 = "asd"; // error
const string &s2 = "asd"; // ok
const string& s3 = f(); // ok
string&& a2 = "defg"; // ok
string&& a3 = f(); // ok
return 0;
}
? 1.4 引入右值引用意義
? 可以延長(zhǎng)右值的生命周期,右值的生命周期可以與右值引用變量相同
2. 完美轉(zhuǎn)發(fā)
2.1? 轉(zhuǎn)發(fā)引用
在 T 是模板參數(shù)時(shí),T&& 的作用主要是保持值類(lèi)別進(jìn)行轉(zhuǎn)發(fā),它有個(gè)名字就叫“轉(zhuǎn)發(fā)引用”(forwarding reference)。因?yàn)榧瓤梢允亲笾狄?,也可以是右值引用,它也曾?jīng)被叫做“萬(wàn)能引用”(universal reference)。
#include<string>
#include<iostream>
using namespace std;
void print(const string& str)
{
cout << "left val: " <<str << endl << endl;
}
void print(string&& str)
{
cout << "right val: " << str <<endl << endl;
}
string ff()
{
return "fff";
}
template<typename T>
void f(T&& param)
{
print(forward<T>(param));
}
int main(int argc, char *argv[])
{
string str1 = "hello 1";
const string& bb = "abc";
const string& bb2 = ff();
f(str1); // left value
f(bb); // left value
f(bb2); // left value
f("abcd"); // rightvalue
f(ff()); // right value
return 0;
}
輸出:
?2.2? 完美轉(zhuǎn)發(fā) std::forward
?2.1.1 源碼解析
- 轉(zhuǎn)發(fā)左值
template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
{ return static_cast<_Tp&&>(__t); }
先通過(guò) remove_reference 獲得類(lèi)型type,定義
_t
為左值引用的左值變量,通過(guò)?static_cast?
進(jìn)行強(qiáng)制轉(zhuǎn)換
- 轉(zhuǎn)發(fā)右值
template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
{
static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
" substituting _Tp is an lvalue reference type");
return static_cast<_Tp&&>(__t);
}
? ?不同于轉(zhuǎn)發(fā)左值,
_t
為右值引用的左值變量,除此之外中間加了一個(gè)斷言,表示當(dāng)不是左值的時(shí)候,也就是右值,才進(jìn)行static_cast
轉(zhuǎn)換。
2.1.2? remove_reference 解析
template<typename _Tp>
struct remove_reference
{ typedef _Tp type; };
// 特化版本
template<typename _Tp>
struct remove_reference<_Tp&>
{ typedef _Tp type; };
template<typename _Tp>
struct remove_reference<_Tp&&>
{ typedef _Tp type; };
remove_reference
的作用是去除T
中的引用部分,只獲取其中的類(lèi)型部分。無(wú)論T
是左值還是右值,最后只獲取它的類(lèi)型部分。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-629737.html
現(xiàn)代C++之萬(wàn)能引用、完美轉(zhuǎn)發(fā)、引用折疊 - 知乎 (zhihu.com)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-629737.html
到了這里,關(guān)于C++ 學(xué)習(xí)系列 1 -- 左值、右值與萬(wàn)能引用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!