1. 程式人生 > >c++11 標準庫函數 std::move 和 完美轉發 std::forward

c++11 標準庫函數 std::move 和 完美轉發 std::forward

標準庫函數 這樣的 除了 值引用 sin 引入 語言 優先 ace

c++11 標準庫函數 std::move 和 完美轉發 std::forward

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <vector>
#include <map>

// C++中還有一個被廣泛認同的說法,那就是可以取地址的、有名字的就是左值,反之,不能取地址的、沒有名字的就是右值。
// 相對於左值,右值表示字面常量、表達式、函數的非引用返回值等。

// 既然編譯器只對右值引用才能調用轉移構造函數和轉移賦值函數,而所有命名對象都只能是左值引用,如果已知一個命名對象不再被使用而想對它調用轉移構造函數和轉移賦值函數,也就是把一個左值引用當做右值引用來使用,怎麽做呢?
// 標準庫提供了函數 std::move,這個函數以非常簡單的方式將左值引用轉換為右值引用。 int a; int &&r1 = a; // 編譯失敗 int &&r2 = std::move(a); // 編譯通過 // 完美轉發 std::forward // 完美轉發適用於這樣的場景:需要將一組參數原封不動的傳遞給另一個函數. // “原封不動”不僅僅是參數的值不變,在 C++ 中,除了參數值之外,還有一下兩組屬性:左值/右值和 const/non-const。 // 完美轉發就是在參數傳遞過程中,所有這些屬性和參數值都不能改變,同時,而不產生額外的開銷,就好像轉發者不存在一樣。在泛型函數中,這樣的需求非常普遍。
// C++11是如何解決完美轉發的問題的呢?實際上,C++11是通過引入一條所謂“引用折疊”(reference collapsing)的新語言規則,並結合新的模板推導規則來完成完美轉發。 typedef const int T; typedef T & TR; TR &v = 1; //在C++11中,一旦出現了這樣的表達式,就會發生引用折疊,即將復雜的未知表達式折疊為已知的簡單表達式 /* C++11中的引用折疊規則: TR的類型定義 聲明v的類型 v的實際類型 T & TR T & T & TR & T & T & TR && T & T && TR T && T && TR & T & T && TR && T && 一旦定義中出現了左值引用,引用折疊總是優先將其折疊為左值引用
*/ // C++11中,std::forward可以保存參數的左值或右值特性 #include <iostream> using namespace std; template <typename T> void process_value(T & val) { cout << "T &" << endl; } template <typename T> void process_value(T && val) { cout << "T &&" << endl; } template <typename T> void process_value(const T & val) { cout << "const T &" << endl; } template <typename T> void process_value(const T && val) { cout << "const T &&" << endl; } //函數 forward_value 是一個泛型函數,它將一個參數傳遞給另一個函數 process_value template <typename T> void forward_value(T && val) //參數為右值引用 { process_value( std::forward<T>(val) ); // C++11中,std::forward可以保存參數的左值或右值特性 } void mytest() { int a = 0; const int &b = 1; forward_value(a); // T & forward_value(b); // const T & forward_value(2); // T && forward_value( std::move(b) ); // const T && return; } int main() { mytest(); system("pause"); return 0; }

c++11 標準庫函數 std::move 和 完美轉發 std::forward