最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++11右值引用與完美轉(zhuǎn)發(fā)及可變參數(shù)模板詳解

 更新時間:2026年02月28日 09:47:32   作者:keyipatience  
文章詳細介紹了C++11中右值引用、引用折疊和完美轉(zhuǎn)發(fā)的概念,以及可變參數(shù)模板的原理和使用,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,感興趣的朋友跟隨小編一起看看吧

1.類型分類

• C++11以后,進?步對類型進?了劃分,右值被劃分純右值(pure value,簡稱prvalue)和將亡值 (expiring value,簡稱xvalue)。

• 純右值是指那些字?值常量或求值結(jié)果相當于字?值或是?個不具名的臨時對象。如: 42、 true、nullptr 或者類似 str.substr(1, 2)、str1 + str2 傳值返回函數(shù)調(diào)?,或者整形 a、b,a++,a+b 等。純右值和將亡值C++11中提出的,C++11中的純右值概念劃分等價于 C++98中的右值。

• 將亡值是指返回右值引?的函數(shù)的調(diào)?表達式和轉(zhuǎn)換為右值引?的轉(zhuǎn)換函數(shù)的調(diào)?表達,如 move(x)、static_cast(x) • 泛左值(generalized value,簡稱glvalue),泛左值包含將亡值和左值,值類別-cppreference.com和Valuecategories這兩個關(guān)于值類型的中?和英?的官??檔,有興趣可以了解細節(jié)

2.引用折疊

 •C++中不能直接定義引?的引?如 int& && r = i; ,這樣寫會直接報錯,通過模板或typedef中的類型操作可以構(gòu)成引?的引?。

• 通過模板或typedef中的類型操作可以構(gòu)成引?的引?時,這時C++11給出了?個引?折疊的規(guī) 則:右值引?的右值引?折疊成右值引?,所有其他組合均折疊成左值引?

 • 下?的程序中很好的展?了模板和typedef時構(gòu)成引?的引?時的引?折疊規(guī)則,?家需要?個? 個仔細理解?下。• 像f2這樣的函數(shù)模板中,T&&x參數(shù)看起來是右值引?參數(shù),但是由于引?折疊的規(guī)則,他傳遞左 值時就是左值引?,傳遞右值時就是右值引?,有些地?也把這種函數(shù)模板的參數(shù)叫做萬能引?。

• Function(T&&t)函數(shù)模板程序中,假設(shè)實參是int右值,模板參數(shù)T的推導(dǎo)int,實參是int左值,模 板參數(shù)T的推導(dǎo)int&,再結(jié)合引?折疊規(guī)則,就實現(xiàn)了實參是左值,實例化出左值引?版本形參的 Function,實參是右值,實例化出右值引?版本形參的Function。

//引用折疊限定f1實例化后總是一個左值引用
template<class T>
void f1(T& x)
{ }
//引用折疊限定f2實例化后可以是一個左值引用,也可以是一個右值引用
template<class T>
void f2(T&& x)
{ }
int main()
{
	typedef int& lref;
	typedef int&& rref;
	int n = 0;
	lref& r1 = n;//r1類型int&
	lref&& r2 = n;//r2類型int&
	rref& r3 = n;//r3類型int&
	rref&& r4 = 1;//r4類型int&&
	//即只要有左值引用折疊后就是左值引用,兩個都是右值引用才是右值引用
	//沒有折疊,實例化為void f1(int&x)
	f1<int>(n);
	//f1<int>(0);//err
	//折疊,實例化為void f1(int&x)
	f1<int&>(n);
	//f1<int&>(0);//err
	//折疊,實例化為void f1(int&x)
	f1<int&&>(n);
	//f1<int&&>(0);//err
	//折疊,實例化為void f1(const int&x)
	f1<const int&>(n);
	f1<const int&>(0);
	//折疊,實例化為void f1(const int&x)
	f1<const int&&>(n);
	f1<const int&&>(0);
	//沒有折疊,實例化為void f2(int&&x)
	//f2<int>(n);//err
	f2<int>(0);
	//折疊,實例化為 void f2(int&x)
	f2<int&>(n);
	//f2<int&>(0);err
	//折疊,實例化為 void f2(int&&x)
	//f2<int&&>(n);err
	 f2<int&&>(0);
	return 0;
}

3.完美轉(zhuǎn)發(fā)

• Function(T&&t)函數(shù)模板程序中,傳左值實例化以后是左值引?的Function函數(shù),傳右值實例化 以后是右值引?的Function函數(shù)。

• 但是結(jié)合我們在5.2章節(jié)的講解,變量表達式都是左值屬性,也就意味著?個右值被右值引?綁定 后,右值引?變量表達式的屬性是左值,也就是說Function函數(shù)中t的屬性是左值,那么我們把t傳 遞給下?層函數(shù)Fun,那么匹配的都是左值引?版本的Fun函數(shù)。這?我們想要保持t對象的屬性, 就需要使?完美轉(zhuǎn)發(fā)實現(xiàn)。

• template T&& forward (typename remove_reference::type& arg); 

•template T&& forward (typename remove_reference::type&& arg);

完美轉(zhuǎn)發(fā)forward本質(zhì)是?個函數(shù)模板,他主要還是通過引?折疊的?式實現(xiàn),下??例中傳遞給 Function的實參是右值,T被推導(dǎo)為int,沒有折疊,forward內(nèi)部t被強轉(zhuǎn)為右值引?返回;傳遞給 Function的實參是左值,T被推導(dǎo)為int&,引?折疊為左值引?,forward內(nèi)部t被強轉(zhuǎn)為左值引? 返回。 

沒有forward即完美轉(zhuǎn)發(fā)前

加了forward即完美轉(zhuǎn)發(fā)后

4.可變參數(shù)模板

4.1 基本語法及原理

 • C++11?持可變參數(shù)模板,也就是說?持可變數(shù)量參數(shù)的函數(shù)模板和類模板,可變數(shù)?的參數(shù)被稱 為參數(shù)包,存在兩種參數(shù)包:模板參數(shù)包,表?零或多個模板參數(shù);函數(shù)參數(shù)包:表?零或多個函 數(shù)參數(shù)。

• template<class...Args> void Func(Args... args) {}

• template<class...Args> void Func(Args&... args) {}

• template<class...Args> void Func(Args&&... args) {}

• 我們?省略號來指出?個模板參數(shù)或函數(shù)參數(shù)的表??個包,在模板參數(shù)列表中,class...或 typename...指出接下來的參數(shù)表?零或多個類型列表;在函數(shù)參數(shù)列表中,類型名后?跟...指出 接下來表?零或多個形參對象列表;函數(shù)參數(shù)包可以?左值引?或右值引?表?,跟前?普通模板 ?樣,每個參數(shù)實例化時遵循引?折疊規(guī)則。

• 可變參數(shù)模板的原理跟模板類似,本質(zhì)還是去實例化對應(yīng)類型和個數(shù)的多個函數(shù)。

模板,一個函數(shù)模板可以實例化出多個不同類型參數(shù)的函數(shù),比如template<class T>這個T可以是int類型,double類型等等

可變參數(shù)模板,一個可變參數(shù)模板實例化出多個不同參數(shù)個數(shù)的模板

4.2 包擴展

• 對于?個參數(shù)包,我們除了能計算他的參數(shù)個數(shù),我們能做的唯?的事情就是擴展它,當擴展?個 包時,我們還要提供?于每個擴展元素的模式,擴展?個包就是將它分解為構(gòu)成的元素,對每個元 素應(yīng)?模式,獲得擴展后的列表。我們通過在模式的右邊放?個省略號(...)來觸發(fā)擴展操作。底層 的實現(xiàn)細節(jié)如圖1所?。

 • C++還?持更復(fù)雜的包擴展,直接將參數(shù)包依次展開依次作為實參給?個函數(shù)去處理。

//方法1:
void showlist()
{
	// 編譯器時遞歸的終?條件,參數(shù)包是0個時,直接匹配這個函數(shù) 
	cout << endl;
}
template<class T,class...Args>
void showlist(T t, Args...args)
{
	cout << t << " ";
	// args是N個參數(shù)的參數(shù)包 
 // 調(diào)?ShowList,參數(shù)包的第?個傳給x,剩下N-1傳給第?個參數(shù)包
	showlist(args...);
}
// 編譯時遞歸推導(dǎo)解析參數(shù) 
template<class...Args>
void print(Args...args)
{
	showlist(args...);
}
//方法2:
template<class T>
const T& GetArg(const T& x)
{
	cout << x << " ";
	return x;
}
template<class...Args>
void Arguments(Args...args)
{
}
template<class...Args>
void print(Args...args)
{
	Arguments(GetArg(args)...);
}
//void Print(int x, string y, double z)
//{
// Arguments(GetArg(x), GetArg(y), GetArg(z));
//}

4.3 emplace系列接口

• template void emplace_back (Args&&... args);

• template iterator emplace (const_iterator position, Args&&... args);

• C++11以后STL容器新增了empalce系列的接?,empalce系列的接?均為模板可變參數(shù),功能上 兼容push和insert系列,但是empalce還?持新玩法,假設(shè)容器為container,empalce還?持 直接插?構(gòu)造T對象的參數(shù),這樣有些場景會更?效?些,可以直接在容器空間上構(gòu)造T對象。

 • emplace_back總體??是更?效,推薦以后使?emplace系列替代insert和push系列

• 第?個程序中我們模擬實現(xiàn)了list的emplace和emplace_back接?,這?把參數(shù)包不段往下傳遞, 最終在結(jié)點的構(gòu)造中直接去匹配容器存儲的數(shù)據(jù)類型T的構(gòu)造,所以達到了前?說的empalce?持 直接插?構(gòu)造T對象的參數(shù),這樣有些場景會更?效?些,可以直接在容器空間上構(gòu)造T對象。

 • 傳遞參數(shù)包過程中,如果是 Args&&... args 的參數(shù)包,要?完美轉(zhuǎn)發(fā)參數(shù)包,?式如下 std::forward(args)... ,否則編譯時包擴展后右值引?變量表達式就變成了左值。

模擬實現(xiàn)List新增加emplace_back等接口

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace bit
{
	template<class T>
	struct list_node
	{
		T _data;
		list_node* next;
		list_node* prev;
		/*list_node(const T& val = T())
			:_data(val)
			, next(nullptr)
			, prev(nullptr)
		{}*/
		list_node() = default;
		template <class... Args>
		list_node(Args&&... args)
			: next(nullptr)
			, prev(nullptr)
			, _data(forward<Args>(args)...)
		{
		}
	};
	template<class T,class ref,class ptr>
	struct list_iterator
	{
		typedef struct list_iterator<T,ref,ptr> self;
		typedef list_node<T> node;
		node* _node;
		list_iterator<T, ref, ptr>(node* nd)
			:_node(nd)
		{}
		ref& operator*()
		{
			//return _node->data;
			return _node->_data;
		}
		ptr* operator->()
		{
			return & _node->_data;
		}
		self& operator++()
		{
			_node = _node->next;
			return *this;
		}
		self& operator--()
		{
			//return _node->prev;
			_node = _node->prev;
			return *this;
		}
		self& operator++(int)
		{
			_node = _node->next;
			return *this;
		}
		self& operator--(int)
		{
			//return _node->prev;
			_node = _node->prev;
			return *this;
		}
		bool operator==(const self& s)const
		{
			return _node == s._node;
		}
		bool operator!=(const self& s)const
		{
			return _node != s._node;
		}
	};
	template<class T>
	class list
	{
	public:
		typedef list_iterator<T,T&,T*> iterator;
		typedef list_iterator<T,const T&, const T*>const_iterator;
		typedef list_node<T> node;
		list<T>()
		{
			empty_init();
		}
		void empty_init()
		{
			_head = new node;
			_head->next = _head;
			_head->prev = _head;
		}
		iterator begin()
		{
			return iterator(_head->next);
		}
		iterator end()
		{
			return iterator(_head);
		}
		const_iterator begin()const
		{
			return const_iterator(_head->next);
		}
		const_iterator end()const
		{
			return const_iterator ( _head);
		}
		template <class... Args>
		iterator insert(iterator pos, Args&&...args)
		{
			node* cur = pos._node;
			node* prev = cur->prev;
			node* newnode = new node(forward<Args>(args)...);
			newnode->next = cur;
			cur->prev = newnode;
			newnode->prev = prev;
			prev->next = newnode;
			return cur;
			++size;
		}
		template <class... Args>
		void emplace_back(Args&&... args)
		{
			insert(end(), forward<Args>(args)...);
		}
		iterator insert(iterator pos, const T& x)
		{
			node* cur = pos._node;
			node* prev = cur->prev;
			node* newnode = new node(x);
			newnode->next = cur;
			cur->prev = newnode;
			newnode->prev = prev;
			prev->next = newnode;
			return cur;
         	++size;
		}
		iterator insert(iterator pos, T&& x)
		{
			node* cur = pos._node;
			node* prev = cur->prev;
			node* newnode = new node(forward<T>(x));
			newnode->next = cur;
			cur->prev = newnode;
			newnode->prev = prev;
			prev->next = newnode;
			return cur;
			++size;
		}
		void pushback(const T& x)
		{
			insert(end(), x);
		}
		void push_back(T&& x)
		{
			insert(end(), forward<T>(x));
		}
		void pushfront(const T& x)
		{
			insert(begin(), x);
		}
		iterator erase(iterator pos)
		{
			assert(pos!=end());
			node* cur = pos._node;
			node* prev = cur->prev;
			node* next = cur->next;
			prev->next = next;
			next->prev = prev;
			delete cur;
			return next;
			--size;
		}
		void popback()
		{
			erase(--end());
		}
		void popfront()
		{
			erase(begin());
		}
		size_t size1()
		{
			return size;
		}
		bool empty()
		{
			return size == 0;
		}
		list<T>(list<T>&l)
		{
			empty_init();
			for (auto& ch : l)
			{
				pushback(ch);
			}
		}
		void swap(list<T>l)
		{
			std::swap(_head, l._head);
			std::swap(size, l.size1());
		}
		list<T>operator=(list<T>tmp)
		{
			swap(tmp);
			return *this;
		}
		void clear()
		{
			auto it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
	private:
		node* _head;
		size_t size;
	};
	template<class container>
	void print( const container& con)
	{
		for (auto ch : con)
		{
			cout << ch << " ";
		}
		cout << endl;
	}
}

到此這篇關(guān)于C++11右值引用與完美轉(zhuǎn)發(fā)及可變參數(shù)模板詳解的文章就介紹到這了,更多相關(guān)c++11右值引用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言使用廣度優(yōu)先搜索算法解決迷宮問題(隊列)

    C語言使用廣度優(yōu)先搜索算法解決迷宮問題(隊列)

    這篇文章主要介紹了C語言使用廣度優(yōu)先搜索算法解決迷宮問題,結(jié)合迷宮問題分析了C語言隊列廣度優(yōu)先搜索算法的相關(guān)使用技巧,需要的朋友可以參考下
    2017-09-09
  • C++之談?wù)剺?gòu)造函數(shù)的初始化列表

    C++之談?wù)剺?gòu)造函數(shù)的初始化列表

    構(gòu)造函數(shù)主要作用在于創(chuàng)建對象時為對象的成員屬性賦值,構(gòu)造函數(shù)由編譯器自動調(diào)用,無須手動調(diào)用,這篇文章詳細介紹了構(gòu)造函數(shù)的初始化列表,文章中有詳細的示例代碼,感興趣的同學可以參考閱讀
    2023-04-04
  • C++實現(xiàn)簡單職工管理系統(tǒng)

    C++實現(xiàn)簡單職工管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C++職工管理系統(tǒng)實訓代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-04-04
  • C++的異常處理詳解

    C++的異常處理詳解

    文章主要介紹了C++異常處理的概念、使用方法及優(yōu)缺點,文章還討論了異常的規(guī)范使用,包括自定義異常體系和C++標準庫的異常體系,并強調(diào)了異常在現(xiàn)代編程中的重要性,感興趣的朋友跟隨小編一起看看吧
    2026-05-05
  • C++實現(xiàn)Armadillo庫與OpenCV庫之間的數(shù)據(jù)格式轉(zhuǎn)換

    C++實現(xiàn)Armadillo庫與OpenCV庫之間的數(shù)據(jù)格式轉(zhuǎn)換

    在C++領(lǐng)域,數(shù)據(jù)格式轉(zhuǎn)換是常見且關(guān)鍵的任務(wù),尤其是在使用多個不同的庫進行復(fù)雜的數(shù)據(jù)處理時,Armadillo和OpenCV是兩個在科學計算和計算機視覺領(lǐng)域非常受歡迎的庫,下面我們將詳細探討如何在C++中實現(xiàn)Armadillo庫與OpenCV庫之間的數(shù)據(jù)格式轉(zhuǎn)換,需要的朋友可以參考下
    2025-03-03
  • C語言結(jié)構(gòu)體版學生成績管理系統(tǒng)

    C語言結(jié)構(gòu)體版學生成績管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言結(jié)構(gòu)體版的學生成績管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • C++ LeetCode1945題解字符串轉(zhuǎn)化后的各位數(shù)字之和

    C++ LeetCode1945題解字符串轉(zhuǎn)化后的各位數(shù)字之和

    這篇文章主要為大家介紹了C++ LeetCode1945題解字符串轉(zhuǎn)化后的各位數(shù)字之和示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • C語言帶頭雙向循環(huán)鏈表的示例代碼

    C語言帶頭雙向循環(huán)鏈表的示例代碼

    這篇文章主要介紹了如何利用C語言實現(xiàn)帶頭雙向循環(huán)鏈表,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-11-11
  • C++簡單實現(xiàn)Dijkstra算法

    C++簡單實現(xiàn)Dijkstra算法

    這篇文章主要為大家詳細介紹了C++簡單實現(xiàn)Dijkstra算法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • Visual Studio 2022卡死分析

    Visual Studio 2022卡死分析

    本文主要介紹了Visual Studio 2022卡死分析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06

最新評論

那曲县| 同心县| 铜川市| 咸阳市| 会东县| 白银市| 福清市| 金川县| 万荣县| 邹城市| 岐山县| 介休市| 巴马| 容城县| 苏尼特右旗| 商河县| 紫金县| 年辖:市辖区| 丹阳市| 驻马店市| 丰台区| 金秀| 五河县| 青海省| 汕尾市| 虎林市| 策勒县| 海伦市| 平武县| 阜南县| 长治市| 大悟县| 左贡县| 宜兰县| 突泉县| 五华县| 大竹县| 桐梓县| 三亚市| 灵川县| 安康市|