【移動語義和精準轉發系列二】std::move和std::forward
在我們開始講解std::move之前,先來介紹一個概念:引用摺疊。這個概念僅用於 typedef 和 模板型別引數 中。
在模板世界中,T&& 稱為Universal Reference,即通用引用。這與普通函式中形參的&&是不同的,希望不要弄混了。
對於模板函式template <typename T> void func(T&& t),對於左值實參,T&& t 推匯出的T為string&;對於右值實參,T&& t 推匯出的T為string。
對於左值引用X&,具有傳染性,即X& &、X& &&和X&& &都摺疊成型別X&;
對於右值引用X&&,只有X&& &&才摺疊成X&&。
下面我們來實戰一下:
template <typename T>
void func(T&& val) {
T t = val;
t++;
if(val == t) { //... }
}
如果傳入的是一個右值42,此時T的型別為int,此時if判斷永遠為false;如果傳入的是一個左值整型變數,則T為int&,此時,if判斷永遠是true。
T&&通常用於兩種情況:模板轉發或模板過載。對於模板過載,通常使用以下方式進行過載:
template <typename T> void func(T&&);
template <typename T> void func(const T&);
好,下面進入正題。
一、先來看一下C++標準原始碼中是怎麼實現std::move模板函式的。
其中,用到了std::remove_reference<_Tp>,這是定義在<type_traits>標頭檔案中的。//<bits/move.h> <utility> /** * @brief Convert a value to an rvalue. * @param __t A thing of arbitrary type. * @return The parameter cast to an rvalue-reference to allow moving it. */ template<typename _Tp> constexpr typename std::remove_reference<_Tp>::type&& move(_Tp&& __t) noexcept { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
// <type_traits>
/// 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; };
根據模板匹配,最終reremove_reference返回的都是脫去引用後的普通型別。所以,std::remove_reference<_Tp>::type&& 一定是該型別的右值引用。雖然不能隱式將一個左值轉換為右值引用,但是我們可以顯式地使用static_cast將一個左值轉換為右值引用。
C++標準規定,對於具名的右值引用,是一個左值;但是,對於一個無名的右值引用,是一個右值。std::move返回的正是一個無名的右值引用,所以是一個右值。這就是強制把一個左值變為右值引用的函式,當然,該函式也可以作用於右值,返回結果仍然是該右值的引用。
此時,肯定有人會說,既然這樣,那為什麼我要用std::move函式,我直接使用static_cast強轉就OK了。是的,雖然我們可以直接使用static_cast進行右值引用強轉,但是,使用標準庫move函式是容易得多的方式。而且,統一使用std::move使得我們在程式中查詢潛在的截斷左值的程式碼變得很容易。
同時,move的名字衝突要比其他標準庫函式的衝突頻繁得多。而且,因為move執行的是非常特殊的型別操作,所以程式專門修改函式原有行為的概率非常小。對move,其實還有forward來說,衝突很多,但大多數是無意的,這一特點解釋了為什麼會使用帶限定語的完整版本的原因。通過書寫std::move而非move,我們就能明確地知道想要使用的是函式的標準庫版本。
二、再來看一下C++標準原始碼中是怎麼實現std::forward模板函式的。
//<bits/move.h> <utility>
// forward (as per N3143)
/**
* @brief Forward an lvalue.
* @return The parameter cast to the specified type.
*
* This function is used to implement "perfect forwarding".
*/
template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
{ return static_cast<_Tp&&>(__t); }
/**
* @brief Forward an rvalue.
* @return The parameter cast to the specified type.
*
* This function is used to implement "perfect forwarding".
*/
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);
}
與move不同的是,forward必須通過顯式模板來呼叫,forward返回該顯式實參型別的右值引用。即:std::forward<T>的返回型別是T&&。顯然,如果T是int&,則T&&仍是int&。如果T是int&&,則T&&仍是int&&。從而forward會保持實參型別的所有細節,包括const,因為對於引用來說,const都是底層的,都會予以保留。
相關推薦
【移動語義和精準轉發系列二】std::move和std::forward
在我們開始講解std::move之前,先來介紹一個概念:引用摺疊。這個概念僅用於 typedef 和 模板型別引數 中。 在模板世界中,T&& 稱為Universal Reference,即通用引用。這與普通函式中形參的&&是不同的,希望不要
【產業智慧官】 用新一代技術+商業作業系統(AI-CPS OS:雲端計算+大資料+物聯網+區塊鏈+人工智慧),在場景中構建狀態感知-實時分析-自主決策-精準執行-學習提升的認知計算和機器智慧
產業智慧官 用新一代技術+商業作業系統(AI-CPS OS:雲端計算+大資料+物聯網+區塊鏈+人工智慧),在場景中構建狀態感知-實時分析-自主決策-精準執行-學習提升的認知計算和機器智慧...
精準控制PWM脈沖的頻率和數量
pen rcc 一個 emp set oid reload rip sub 在一些項目中,我們經常要控制PWM脈沖的頻率和數量,比如步進電機的控制等,下面分享一個程序是關於這方面的,程序的思想就是通過STM32的定時器來輸出PWM波,並開啟定時器中斷,在中斷裏面計數脈沖
【重磅來襲:系列二】史上最全NB-IoT技術方面的系列問題和聯盟答案
zdb 史上最全 post lnl gyb nb-iot技術 dsd cxx target 1p賀新艙jp蔔裝鏈5f杖家醞http://bgjxld.wikidot.com/nv涯匱巴zt凹舷感9a溫悠舊http://zmzjsz.wikidot.com/lx猶鍁匭3d拭謨
獲取深度和法線紋理 背後的原理【Unity Shader入門精要13.1.1】
13.1.1背後的原理 什麼是深度紋理: 實際上就是一張渲染紋理,只不過它裡面儲存的畫素值不是顏色值,而是一個高精度的深度值,由於被儲存在一張紋理中,深度紋理裡的深度範圍是[0,1],而且通常是 非線性分佈的。 深度值來自頂點變換後得到的歸一化的裝置座標(Normali
IDEA神器使用技巧和快捷鍵總結之精準搜尋(二)
搜尋相關快捷鍵 搜尋類,ctrl+N。如果想搜尋Jar包裡的類,那麼需要在搜尋類的篩選條件處點選Include non-project items選項,就可以檢視Jar包裡的類了 搜尋檔案,c
協助科學家建立機器學習模型 讓進行速度和精準度優化
IBM是一個數據科學應用程式開發工具Watson Studio,添加了一系列人工智慧自動化功能AutoAI,幫助資料科學家解決構建
c++11 標準庫函數 std::move 和 完美轉發 std::forward
標準庫函數 這樣的 除了 值引用 sin 引入 語言 優先 ace c++11 標準庫函數 std::move 和 完美轉發 std::forward #define _CRT_SECURE_NO_WARNINGS #include <iostream>
WebService系列二:使用JDK和CXF框架開發WebService
method IT ebean pri build 實例 cxf 地址 result 一、使用JDK開發WebService 服務端程序創建: 1.新建一個JDK開發webservice的服務端maven項目JDKWebServiceServer 2. 定義一個接口,
【無人駕駛系列二】基於ROS的無人駕駛系統
本文是無人駕駛技術系列的第二篇。在上篇解析光學雷達(LiDAR)技術之後,本文著重介紹基於機器人作業系統ROS的無人駕駛系統。文中將介紹ROS以及它在無人駕駛場景中的優缺點,並討論如何在ROS的基礎上提升無人駕駛系統的可靠性、通訊效能和安全性。 無人駕駛:多種技術的整合 無人駕駛技術是多個
【數字影象處理系列二】基本概念:亮度、對比度、飽和度、銳化、解析度
本系列python版本:python3.5.4 本系列opencv-python版本:opencv-python3.4.2.17 本系列使用的開發環境是jupyter notebook,是一個python的互動式開發環境,測試十分方便,並集成了vim
SpringBoot框架搭建系列(二):整合pagehelper和mybatis-generator
本次我們整合mybatis的分頁外掛pagehelper,以及mapper自動生成的外掛mybatis-generator 先整合mybatis-generator 1、在pom中引入 <plugin> <groupId
rxJava和rxAndroid原始碼解析系列二之observer訂閱
建立完Observable物件後,以後一步ObservableObserveOn.subscribe(new Observer<String>() {.....})這一步又發生了什麼呢? 接著跟蹤原始碼。 @SchedulerSupport(Schedu
【Spring筆記二】關於IOC和DI
IOC(Inversion of Control,反轉控制) 所謂的 IOC是指在程式設計中,例項不再由呼叫者來建立,而是由Spring容器來建立。簡單說就是建立物件由以前的程式設計師自己new 構造方法來呼叫,變成了交由Spring建立物件 。 以獲取物件的方式來進行比
【移動端適配方案一 彈性佈局】@media標籤+rem+viewport實現移動端螢幕適配
一、從設計稿說起:採用rem來佈局,其實設計稿是多大都沒有關係,設計稿給480、600或者750都可以,其他尺寸也可以,你就想成它是一張A4紙,然後這些數字只是對這張紙的最大計量單位。反正一張圖就那麼大,無論計量單位是多少,UI設計師能夠在一張A4上給的東西都是一樣的。比如說
【網路基本功系列二】細說交換機
記住交換機操作模式的一句簡單的話是:交換機學習“源地址”,基於“目的地址”轉發。幀進入交換機時,交換機“學習”接收幀的源MAC地址,並將此地址新增到MAC地址表中,或重新整理已存在的MAC地址表項的老化暫存器;後續報文如果去往該MAC地址,則可以根據此表項轉發。幀轉發時,交換機檢查目的MAC地址並與MAC地址
【H3C V7路由器實戰視訊課程系列-5】可靠性功能配置與管理-王達-專題視訊課程...
【H3C V7路由器實戰視訊課程系列-5】可靠性功能配置與管理—99人已學習 課程介紹 本課程以實戰方式系統地介紹了H3C路由器中有關BFD、NQA、VRRP和Track功能的技術原理和配置與管理方法。課程收益 輕鬆掌握BFD、NQA、VRRP和Track
Hadoop系列二:啟動HDFS和YARN過程日誌
以下記錄為啟動HDFS和YARN環境時的過程中的中間過程輸出,節點註冊 和 HDFS檔案系統的資料變化日誌等。 (1)執行HDFS檔案系統格式化 [[email protected] hadoop]$ $HADOOP_PREFIX/bin/hdfs name
系列二、spirngMVC view和controller引數相互傳遞
在之前的學習中我們都知道,獲取view層傳遞過來的引數,我們一般的都是key,value鍵-值對的形式,在servlet控制器中使
【數量技術宅|金融資料分析系列分享】為什麼中證500(IC)是最適合長期做多的指數
更多精彩內容,歡迎關注公眾號:數量技術宅。探討資料分析、量化投資問題,請加技術宅微信:sljsz01 投資股票指數相比個股的優勢 我們在投資股票的時候,如果持倉集中在一隻或者有限幾隻股票上,恰好不幸遇到“長生生物”、“康美藥業”這樣造假、暴雷的公司,將會對賬戶總資產造成極大的損失。可以說選股是一門極度需要