C++11 左值引用和右值引用與引用摺疊和完美轉發

拾荒荒發表於2021-07-23

1.左值與右值

最感性的認識。

當然,左值也是可以在右邊的。

左值是可以被修改的,右值不能。

當然取地址也是。

生存週期一般左值會比右值的長,一般右值都計算時產生的無名臨時物件,存在時間比較短。

下面還有一種情況也要區分。

2.左值引用和右值引用

左值引用:可以引用一個物件,有時候也可以繫結一個右值。

右值引用:只能引用右值。

1左值引用示例

看以下程式碼,比較正常。

	int a = 3;
	int &p1 = a;  // 左值引用

若左值引用右值將報錯

但加上const就可以引用了

2右值引用示例

不能把左值繫結到右值,但使用move可以把左值轉換右值就可以繫結

示例1

示例2

示例3

理解了上邊知識,接下來是引用摺疊規則,

3.引用摺疊

先看演示程式碼

#include <iostream>
using namespace std;

using lRef = int&;   //左值引用
using rRef = int&&;	 //右值引用

int main(int argc, char **argv)
{
	is_lvalue_reference<lRef &>::value ?
		cout << "lRef &  左值引用" << endl :
		cout << "lRef &  右值引用" << endl;

	is_lvalue_reference<lRef &&>::value ?
		cout << "lRef && 左值引用" << endl :
		cout << "lRef && 右值引用" << endl;


	is_rvalue_reference<rRef &>::value ?
		cout << "rRef &  右值引用" << endl :
		cout << "rRef &  左值引用" << endl;

	is_rvalue_reference<rRef &&>::value ?
		cout << "rRef && 右值引用" << endl :
		cout << "rRef && 左值引用" << endl;


	return 0;
}

除錯結果

這就是引用摺疊規則。

這怎麼理解呢,看下圖

可以看到只有都是右值引用的時候才是右值引用,當然只有一個右值引用的情況下自然而然也是右值引用。

這是就引用摺疊。

4.完美轉發

主要用於引數轉發時是左值傳入還是右轉入
考慮以下程式碼

#include <iostream>
using namespace std;

template<typename T> 
void Fun1(T& v)
{
	cout << "左值引用呼叫" << v << endl;
}

template<typename T>
void Fun1(T&& v)
{
	cout << "右值引用呼叫" << v <<endl;
}

template<typename T>
void Fun(T&& v)
{
	Fun1(v);
}

int main(int argc, char **argv)
{
	int a = 3;

	Fun(a);

	return 0;
}

主函式裡給Fun傳入a,根據上邊知識,a是一個左值,看除錯結果是呼叫哪一個過載版本Fun1

結果跟預想的一樣,接下來更改換右值傳入。

int main(int argc, char **argv)
{

	Fun(5);

	return 0;
}

除錯結果

我們發現跟想象中不一樣!!!

這時候該怎麼辦。

c++11中提供了一個用於完美轉發的函式forward。

還提供了一個move函式,用於把左值變成右值的方法。

forward會根據引用摺疊規則得出傳入的是左值引用還是右值引用

接下來只需更改一下Fun函式,其他的不變

template<typename T>
void Fun(T&& v)
{
	Fun1(forward<T>(v));
}

除錯結果

發現跟我們預想一樣了。

完美轉發完整示例

#include <iostream>
using namespace std;

template<typename T> 
void Fun1(T& v)
{
	cout << "左值引用呼叫" << v << endl;
}

template<typename T>
void Fun1(T&& v)
{
	cout << "右值引用呼叫" << v <<endl;
}

template<typename T>
void Fun(T&& v)
{
	Fun1(forward<T>(v));
}

int main(int argc, char **argv)
{
	int a = 1;
	Fun(a);
	Fun(move(a));

	const int b = 2;
	Fun(b);
	Fun(move(b));

	Fun(5);

	return 0;
}

除錯結果

5.結語

學無止境。
---End

相關文章