1. 程式人生 > >【移動語義和精準轉發系列二】std::move和std::forward

【移動語義和精準轉發系列二】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模板函式的。

//<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); }
其中,用到了std::remove_reference<_Tp>,這是定義在<type_traits>標頭檔案中的。
// <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::movestd::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系列:使用JDKCXF框架開發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框架搭建系列():整合pagehelpermybatis-generator

本次我們整合mybatis的分頁外掛pagehelper,以及mapper自動生成的外掛mybatis-generator 先整合mybatis-generator 1、在pom中引入 <plugin> <groupId

rxJavarxAndroid原始碼解析系列之observer訂閱

建立完Observable物件後,以後一步ObservableObserveOn.subscribe(new Observer<String>() {.....})這一步又發生了什麼呢? 接著跟蹤原始碼。 @SchedulerSupport(Schedu

Spring筆記關於IOCDI

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系列:啟動HDFSYARN過程日誌

以下記錄為啟動HDFS和YARN環境時的過程中的中間過程輸出,節點註冊 和 HDFS檔案系統的資料變化日誌等。 (1)執行HDFS檔案系統格式化 [[email protected] hadoop]$ $HADOOP_PREFIX/bin/hdfs name

系列、spirngMVC viewcontroller引數相互傳遞

在之前的學習中我們都知道,獲取view層傳遞過來的引數,我們一般的都是key,value鍵-值對的形式,在servlet控制器中使

數量技術宅|金融資料分析系列分享為什麼中證500(IC)是最適合長期做多的指數

更多精彩內容,歡迎關注公眾號:數量技術宅。探討資料分析、量化投資問題,請加技術宅微信:sljsz01 投資股票指數相比個股的優勢 我們在投資股票的時候,如果持倉集中在一隻或者有限幾隻股票上,恰好不幸遇到“長生生物”、“康美藥業”這樣造假、暴雷的公司,將會對賬戶總資產造成極大的損失。可以說選股是一門極度需要