C++模板元編程(二)——完美轉發

完美轉發指的是函數模板可以將自己的參數“完美”地轉發給內部調用的其它函數。所謂完美,即不僅能準確地轉發參數的值,還能保證被轉發參數的左、右值屬性不變。


文章目錄

  • 場景
  • 舊的方法
  • 新的方法
  • 內部實現
  • 參考文獻


場景

思考下面的代碼:

template<typename T>
void function(T t) {otherfunc(t);
}

function() 函數模板中調用了otherfunc()函數。我們想要的完美轉發是:

  • 如果function()函數接收到的參數 t 為左值,那么該函數傳遞給 otherfunc() 的參數 t 也是左值。
  • 如果function()函數接收到的參數t為右值,那么傳遞給 otherfunc() 函數的參數 t 也是右值

顯然 function() 函數模板沒有實現完美轉發,這是因為無論是左值還是右值傳遞進來,都會當作是左值,因為是非引用類型。

比如 function(10); 傳遞給 otherfunc() 也是左值而不是我們期望的右值,這在我們期望對左值和右值進行不同處理時會產生問題。


舊的方法

在C++98/03 標準下的 C++ 也可以實現完美轉發,只是實現方式比較麻煩。

C++98/03 標準中只有左值引用,可以細分為非 const引用和const引用:

  • 非const引用作為函數模板參數,只能接收左值無法接收右值
  • const左值引用既可以接收左值,也可以接收右值,但如果內部需要將參數傳遞給其他函數,需要被調用函數的參數也是 const,否則無法直接傳遞

可見能實現轉發,但不夠"完美"。

#include <iostream>
using namespace std;
//重載被調用函數,查看完美轉發的效果
void otherfunc(int & t) {cout << "call lvalue\n";
}
void otherfunc(const int & t) {cout << "call rvalue\n";
}//重載函數模板,分別接收左值和右值
//接收右值參數
template <typename T>
void function(const T& t) {otherfunc(t);
}
//接收左值參數
template <typename T>
void function(T& t) {otherfunc(t);
}
int main()
{function(10);//10 是右值int  x = 2;function(x);//x 是左值return 0;
}

輸出為

左值實參既能匹配 function(T& t) 也能匹配 function(const& t),編譯器會選擇更合適的 function(T& t)


新的方法

對于舊的方法,當模板函數有大量參數的情況,可能就需要編寫大量的重載函數模板。

在C++11標準中引入了右值引用,通常情況下右值引用只能接收右值,而對于函數模板中使用右值引用語法定義的參數來說,它既可以接收右值,也可以接收左值(稱為萬能引用)。

因此在C++11標準中實現完美轉發,只需要編寫如下一個模板函數即可:

template <typename T>
void function(T&& t) {otherdef(t);
}

但是還存在一個問題,如果我們傳入的參數是一個左值引用或右值引用的實參,如下所示:

int x = 5;
int& y =  x;
function(y); // T為int&
int&& z = 1;
function(z); // T 為int&&

其中, function(y) 實例化的函數為 function(int& && t),由function(z) 實例化的函數為 function(int&& &&t),這在C++98/03是不支持的,而C++11引入了引用折疊規則:

  • 當實參為左值或者左值引用(A&)時,函數模板中 T&& 將轉變為 A&,即 A& && = A&
  • 當實參為右值或者右值引用(A&&)時,函數模板中 T&& 將轉變為 A&&,即 A&& && = A&&

還存在的問題是,在function()函數內部,不管是 T& t 還是 T&& t 其實 t 都是一個左值,因此都會傳遞到 otherfunc(int& t)

所以我們需要一種解決方案來處理這個問題,C++11標準里的模板函數 forward() 就是用來解決這個問題,讓我們能傳遞左值/右值屬性,例子如下:

#include <iostream>
using namespace std;
//重載被調用函數,查看完美轉發的效果
void otherfunc(int & t) {cout << "lvalue\n";
}
void otherfunc(const int & t) {cout << "rvalue\n";
}
//實現完美轉發的函數模板
template <typename T>
void function(T&& t) {otherfunc(forward<T>(t));
}
int main()
{function(1);int  x = 2;function(x);return 0;
}

輸出如下,正確傳遞了左值/右值屬性


內部實現

下面簡單看下內部實現(MSVC)

_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept {return static_cast<_Ty&&>(_Arg);
}_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept {static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");return static_cast<_Ty&&>(_Arg);
}

簡單地來說就是通過靜態的強制類型轉換+引用折疊,返回對應的結果。

比如下面的四鐘情況:

	int x = 2;otherfunc(forward<int>(x)); // 匹配第一個,返回 int&&otherfunc(forward<int>(2)); // 匹配第二個,返回 int&&int& y = x;otherfunc(forward<int&>(y)); // 匹配第一個,返回 int&int&& z = 2;otherfunc(forward<int&&>(z)); // 匹配第一個,返回 int&&,可見右值引用是個左值

它的輸出結果如下


參考文獻

C++11、C++14、C++17、C++20新特性總結(5萬字詳解)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/42362.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/42362.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/42362.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

高防服務器的重要性

在數字化時代&#xff0c;網絡安全已成為企業和個人最為關注的問題之一。隨著網絡攻擊的日益頻繁和復雜&#xff0c;傳統的服務器租用服務已難以滿足高安全需求的市場。高防服務器租用應運而生&#xff0c;成為保護網絡安全的重要解決方案。本文將探討高防服務器租用的概念、重…

專業140+總分420+天津大學815信號與系統考研經驗天大電子信息與通信工程,真題,大綱,參考書。

順利上岸天津大學&#xff0c;專業課815信號與系統140&#xff0c;總分420&#xff0c;總結一些自己的復習經歷&#xff0c;希望對于報考天大的同學有些許幫助&#xff0c;少走彎路&#xff0c;順利上岸。專業課&#xff1a; 815信號與系統&#xff1a;指定教材吳大正&#xf…

2-26 基于matlab開發的制冷循環模型

基于matlab開發的制冷循環模型。Simscape兩相流域中的制冷循環模型&#xff0c;在simulink中完成多循環溫度控制。程序已調通&#xff0c;可直接運行。 2-26 制冷循環模型 Simscape兩相流域 - 小紅書 (xiaohongshu.com)

Arduino ESP8266 開發環境搭建

Arduino ESP8266 開發環境搭建 很久之前學嵌入式時&#xff0c;用過Arduino8266進行開發&#xff0c;開發成本低、難度小&#xff0c;體驗很不錯。 近期&#xff0c;又突然要用&#xff0c;遂再次搭建環境&#xff0c;但變動挺多&#xff0c;有些小波折&#xff0c;開貼記錄。…

生成式AI應用實列和價值鏈

生成式AI應用實列和價值鏈 生成式AI應用實列ChatGPTGeminiGitHub CopilotSynthesia 價值鏈 生成式AI應用實列 ChatGPT ChatGPT 并不是生成式 AI 行業中唯一的公司。 Stability AI 的 Stable Diffusion 可以根據文本描述生成圖像&#xff0c;發布后 90 天內&#xff0c;在 Git…

vue是如何進行監聽數據變化的?vue2和vue3分別是什么,vue3為什么要更換

在 Vue 中&#xff0c;數據變化的監聽是通過響應式系統來實現的。Vue 2.x 和 Vue 3 在這方面有一些區別。 Vue 2.x 的數據監聽 Vue 2.x 使用的是 Object.defineProperty() 方法來實現數據的響應式。當你聲明一個 Vue 實例的數據對象時&#xff0c;Vue 將遍歷這個對象的屬性&a…

清除屏幕上信息的命令clear

清除屏幕上信息的命令clear There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated should leave quickly. 清…

高考志愿填報千萬要注意這四點

在高考志愿填報過程中&#xff0c;確實有很多需要留心的點。我為你總結了四個關鍵點&#xff0c;希望能幫助你順利完成志愿填報&#xff1a; 1、學校提供的支持 學校作為學生志愿填報咨詢服務的主陣地&#xff0c;應提供體系化和制度化的支持。包括及時關注并傳達政策動向和相…

行內元素、塊級元素居中

行內元素居中 水平居中 {text-align&#xff1a;center;}垂直居中 單行——行高等于盒子高度 <head><style>.father {width: 400px;height: 200px;/* 行高等于盒子高度&#xff1a;line-height: 200px; */line-height: 200px;background-color: pink;}.son {}&…

如何做好IT類的技術面試?

我們在找工作時&#xff0c;需要結合自己的現狀&#xff0c;針對意向企業做好充分準備。作為程序員&#xff0c;你有哪些面試IT技術崗的技巧&#xff1f; 方向一&#xff1a;分享你面試IT公司的小技巧 我分享一些基于廣泛觀察和用戶反饋的面試IT公司的小技巧&#xff1a; 技術準…

孟德爾隨機化-痛風

寫在前面 昨天看到文獻&#xff0c;稱飲酒與痛風無關聯&#xff0c;甚是疑惑&#xff0c;今天剛好看了一篇新文獻&#xff0c;雖然不是主要講飲酒與痛風的&#xff0c;但也有牽扯到這方面內容&#xff0c;而且是相反的內容&#xff0c;特記錄一下。 孟德爾隨機化-受教育程度與…

vuepress創建步驟

背景 記錄vuepress配置步驟&#xff0c;以便下次使用快速上手。 讀此文章之前默認您已經學會了創建vuepress項目。vuepres快速開始 最終成品 doc.jeecgflow.com 配置步驟 創建.vuepress 目錄。 你的文檔目錄下創建一個 .vuepress 目錄。 創建.vuepress/config.js module.e…

mysql面試題 Day4

1 什么是覆蓋索引&#xff1f;對要查詢的列 和 查詢條件中的列 有什么要求 覆蓋索引&#xff08;Covering Index&#xff09;是指一個索引包含了一次查詢所需的全部列&#xff0c;因此可以完全滿足查詢需求&#xff0c;而無需訪問實際的表行數據。&#xff08;即避免回表操作&…

Mac窗口輔助管理工具:Magnet for mac激活版

magnet mac版是一款運行在蘋果電腦上的一款優秀的窗口大小控制工具&#xff0c;拖拽窗口到屏幕邊緣可以自動半屏&#xff0c;全屏或者四分之一屏幕&#xff0c;還可以設定快捷鍵完成分屏。這款專業的窗口管理工具當您每次將內容從一個應用移動到另一應用時&#xff0c;當您需要…

注意力機制 attention Transformer 筆記

動手學深度學習 這里寫自定義目錄標題 注意力加性注意力縮放點積注意力多頭注意力自注意力自注意力縮放點積注意力&#xff1a;案例Transformer 注意力 注意力匯聚的輸出為值的加權和 查詢的長度為q&#xff0c;鍵的長度為k&#xff0c;值的長度為v。 q ∈ 1 q , k ∈ 1 k …

解析Java中的緩存機制及其實現方式

解析Java中的緩存機制及其實現方式 大家好&#xff0c;我是微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 在軟件開發中&#xff0c;緩存是一種常見的優化技術&#xff0c;用于臨時存儲數據&#xff0c;以提高數據訪問速度…

【WEB前端2024】3D智體編程:喬布斯3D紀念館-第54課-poplang語音編程控制機器人

【WEB前端2024】3D智體編程&#xff1a;喬布斯3D紀念館-第54課-poplang語音編程控制機器人 使用dtns.network德塔世界&#xff08;開源的智體世界引擎&#xff09;&#xff0c;策劃和設計《喬布斯超大型的開源3D紀念館》的系列教程。dtns.network是一款主要由JavaScript編寫的…

【TORCH】神經網絡權重初始化和loss為inf

文章目錄 數據輸入范圍和權重初始化數據范圍對權重初始化的影響示例代碼輸入數據標準化 說明其他注意事項 常見初始化方法常見的權重初始化方法示例代碼說明 模型默認初始化方法&#xff0c;會不會導致Loss為inf示例說明初始化權重導致 Loss 為 inf避免 Loss 為 inf 的建議示例…

SQL 對一個經常有數據更新和刪除操作的表,怎樣優化以減少磁盤空間的占用?

文章目錄 一、定期清理不再需要的數據二、使用合適的數據類型三、壓縮數據四、刪除重復數據五、分區表六、索引優化七、碎片整理八、歸檔歷史數據九、監控和評估 在數據庫管理中&#xff0c;當面對一個經常進行數據更新和刪除操作的表時&#xff0c;磁盤空間的有效利用是一個重…

Pogo-DroneCANPWM模塊:可實現DroneCAN轉PWM,DroneCAN轉dshot,DroneCAN轉bdshot

關鍵詞&#xff1a;Ardupilot&#xff0c;Pixhawk&#xff0c;PWM&#xff0c;dshot&#xff0c;bdshot&#xff0c;DroneCANPWM&#xff0c;電調ESC&#xff0c;DroneCAN&#xff0c;UAVCAN&#xff0c;飛控&#xff0c;無人機&#xff0c;UAV Keywords&#xff1a;Ardupilot…