国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

forward在委托機(jī)制中的應(yīng)用——完美轉(zhuǎn)發(fā)

2019-11-10 22:57:25
字體:
供稿:網(wǎng)友

一.前言

在之前,我曾花三篇文章講述了C++委托機(jī)制的封裝,到最后可以實(shí)現(xiàn)任意類型函數(shù)的捆綁,包括lambda表達(dá)式的注冊。然而,這個委托機(jī)制還有一點(diǎn)需要完善,可能看標(biāo)題大家知道這個需要完善的點(diǎn)兒是什么,不過不知道也關(guān)系,這個文章會由淺入深的講述這個問題的來源,以及解決方案。

二.問題引入

在直接上委托代碼之前我們先抽出問題本質(zhì),用簡單的代碼來發(fā)現(xiàn)問題,例子來源于<C++ PRimer>P612: 這個將編寫一個Agent函數(shù),它負(fù)責(zé)接受一個函數(shù)和兩個參數(shù),并且用這個函數(shù)來調(diào)用這兩個參數(shù)。

template<typename Function,typename Param1,typename Param2>void Agent(Function f,Param1 p1,Param2 p2){ f(p1,p2);}

這個函數(shù)就相當(dāng)于委托的一個雛形,一般情況下,這個函數(shù)能工作得很好,然而在當(dāng)f的實(shí)例是一個接受引用參數(shù)的函數(shù)就會出現(xiàn)問題,因?yàn)闊o論左右值在模板的類型推演的過程中是不會帶引用的。例如:

template<typename T>void f(T a){}f(1) -> T為intint a;f(a) -> T為int

如何解決這個問題呢?這里有兩種方案:

1.使用move()或者ref()來”提醒”模板推演成引用類型。

class A{public: A() { cout << "構(gòu)造" << endl; } A(const A&) { cout << "拷貝" << endl; } A(A&&) { cout << "移動" << endl; }};template<typename T>void X(T a) { }int main(){ A a; X(ref(a)); X(move(a)); return 0;}

以上方法雖然在這種情況下能夠解決問題,然而在實(shí)際過程中還是會有許多局限性:

在參數(shù)轉(zhuǎn)發(fā)路徑上始終要記住保持參數(shù)類型。也就是如果轉(zhuǎn)發(fā)層數(shù)過多,那么參數(shù)類型在中途可能還是會有部分修飾丟失。調(diào)用形式始終要和函數(shù)參數(shù)類型保持一致,不利于維護(hù)。

那么,我們就比較希望能夠有一種方式能夠使得參數(shù)在轉(zhuǎn)發(fā)的路途中始終保持自身的完整類型。而這個方法就是forward.

三.引用折疊

在講forward之前需要引入一個新的概念——引用的折疊。 我們知道在C++語法中規(guī)定不能定義引用的引用。然而,可能有部分同學(xué)寫過如下代碼:

typedef int& rint;int a = 5;rint b = a;rint& c = b;

而且,這段代碼是編譯通過的,可能有人就會說,經(jīng)過換名之后 rint&就是引用的引用。 然而實(shí)際上對于編譯器而言rint& 實(shí)質(zhì)就是 int& & <——請注意,兩個&之間有空格。 根據(jù)不同的換名可能會有以下幾種情況: - T& & - T&& & - T& && - T&& &&

然而對于這些情況,編譯器會發(fā)生引用折疊,如下:

原型 折疊后
T& & T&
T&& & T&
T& && T&
T&& && T&&

所以說利用模板推演和引用折疊可以找到參數(shù)的真正類型。

四.forward的使用——prefect forward

首先我們來看forward的源碼

template<class _Ty> inlineconstexpr _Ty&& forward( typename remove_reference<_Ty>::type& _Arg) _NOEXCEPT{ // forward an lvalue as either an lvalue or an rvalue return (static_cast<_Ty&&>(_Arg));}template<class _Ty> inlineconstexpr _Ty&& forward( typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT{ // forward an rvalue as an rvalue static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call"); return (static_cast<_Ty&&>(_Arg));}

可見forward是有兩個版本的,下面給出上面英文的注解的翻譯

將一個左值實(shí)參按照其真實(shí)類型(左值或者右值)轉(zhuǎn)發(fā)(轉(zhuǎn)換)。將一個右值按照右值類型轉(zhuǎn)發(fā)(轉(zhuǎn)換)。

由于篇幅原因我就只剖析第一個重載版本。剖析之前,我還是先要介紹forward的使用。 雖然forward是模板函數(shù),參數(shù)可以自動推演,然而forward的參數(shù)是一個remove_reference萃取后的類型,也就是我們可以推演出remove_reference<_Ty>::type,但是無法推演出_Ty。 所以使用過程中,我們還是要顯式給出_Ty;例如: forward< T >(obj)。

所以_Ty就是我們提供的類型T。 至于remove_reference< T > 作用就是去掉類型T的所有引用修飾。也就是說假如T為Type&或者Type&&,那么remove_reference< T >::type就是Type。這個模板是標(biāo)準(zhǔn)庫提供的標(biāo)準(zhǔn)類型轉(zhuǎn)換模板,為了方便閱讀,我將其余的一些貼在了文章的最末。 根據(jù)上一段講述的引用折疊我們知道_Ty&&折疊后就是_Ty的真正類型。 所以forward就是將左值實(shí)參按照給定的類型T進(jìn)行強(qiáng)轉(zhuǎn)。

了解了forward實(shí)現(xiàn)之后,我們來改寫上面的Agent函數(shù):

template<typename Function,typename Param1,typename Param2>void Agent(Function f,Param1&& p1,Param2&& p2){ f(forward<Param1>(p1),forward<Param2>(p2));}

這樣,當(dāng)我將左值int傳入第一個參數(shù)的時(shí)候,Param1會根據(jù)引用折疊原理自動推演為int&而在調(diào)用f的過程中使用forward< Param1 >(p1)將p1保持Param1類型。

根據(jù)這個我改寫了委托的代碼,如下(在這里使用了模板參數(shù)包的展開技巧):

template<typename T>class Delegate{};template<typename Return, typename...Params>class Delegate<Return(Params...)>{public: typedef Return (*FunType) (Params...); Delegate(FunType fun) :_fun(fun) {} Return Operator () (Params... params) { return _fun(forward<Params>(params)...); //注意:這里使用了模板參數(shù)包的展開技巧 }private: FunType _fun;};void fun(int&& a) { cout << a << endl; }int main(){ Delegate<void(int&&)> a(fun); a(2); return 0;}

*五.標(biāo)準(zhǔn)類型轉(zhuǎn)換模板

名稱 若T為 則Mod< T >::type為 否則Mod< T >::type為
remove_reference X&或者X& X T
add_const X&、const X 或者函數(shù) T const T
add_lvalue_reference X&或者X&& X& T&
add_rvalue_reference X&或者X&& X&& T&&
remove_pointer X* X T
add_pointer X&或者X&& X* T*
make_signed unsigned X X T
make_unsigned 帶符號類型 unsigned X T
remove_extent X[n] X T
remove_all_extents X[n1][n2]… X T

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 伊宁县| 五指山市| 遂宁市| 门源| 兴义市| 屏山县| 丹阳市| 科技| 定兴县| 安阳县| 三门峡市| 淮阳县| 新邵县| 连城县| 岳阳市| 碌曲县| 平昌县| 达日县| 遵义县| 江阴市| 和平县| 鸡泽县| 龙南县| 安岳县| 荥经县| 来宾市| 榆中县| 大名县| 南开区| 桑日县| 文昌市| 池州市| 固阳县| 顺平县| 吴旗县| 静安区| 金乡县| 托里县| 清涧县| 永州市| 新丰县|