原文有部分紕漏
https://zhuanlan.zhihu.com/p/161039484
根據(jù)知友的辨析作了修改
std::move它的作用是無論你傳給它的是左值還是右值水慨,通過std::move之后都變成了右值肌似。而今天我們要介紹的std::forward則與之不同锭亏,它的作用是什么呢捏鱼?
forward的作用
std::forward被稱為完美轉(zhuǎn)發(fā)憔足,它的作用是保持原來的值屬性不變。啥意思呢酒繁?通俗的講就是,如果原來的值是左值控妻,經(jīng)std::forward處理后該值還是左值州袒;如果原來的值是右值,經(jīng)std::forward處理后它還是右值弓候。
看看下面的例子郎哭,你應(yīng)該就清楚上面這句話的含義了:
#include <iostream>
template<typename T>
void print(T & t){
std::cout << "左值" << std::endl;
}
template<typename T>
void print(T && t){
std::cout << "右值" << std::endl;
}
template<typename T>
void testForward(T && v){
print(v);
print(std::forward<T>(v));
print(std::move(v));
}
int main(int argc, char * argv[])
{
testForward(1);
std::cout << "======================" << std::endl;
int x = 1;
testFoward(x);
}
//clang++ -std=c++11 -g -o forward test_forward.cpp
知友辨析:這里有點小漏洞,print(std::forward<T>(v))這句話中菇存,假如進入的是右值的那個模板函數(shù)夸研,此時的T=int,你這樣轉(zhuǎn)換的話有問題依鸥,沒有體現(xiàn)出v是右值類型通過forward轉(zhuǎn)出右值亥至,正確做法應(yīng)該是print(std::forward<decltype(v)>(v))
在上面的代碼中,定義了兩個模板函數(shù)贱迟,一個接收左值姐扮,另一個接收右值。在testForward函數(shù)中向模板函數(shù)print傳入不同的參數(shù)衣吠,這樣我們就可以觀察出forward與move的區(qū)別了茶敏。
上面代碼執(zhí)行結(jié)果如下:
左值
右值
右值
=========================
左值
左值
右值
從上面第一組的結(jié)果我們可以看到,傳入的1雖然是右值缚俏,但經(jīng)過函數(shù)傳參之后它變成了左值(在內(nèi)存中分配了空間)惊搏;而第二行由于使用了std::forward函數(shù),所以不會改變它的右值屬性忧换,因此會調(diào)用參數(shù)為右值引用的print模板函數(shù)恬惯;第三行,因為std::move會將傳入的參數(shù)強制轉(zhuǎn)成右值包雀,所以結(jié)果一定是右值宿崭。
再來看看第二組結(jié)果。因為x變量是左值才写,所以第一行一定是左值葡兑;第二行使用forward處理,它依然會讓其保持左值赞草,所以第二也是左值讹堤;最后一行使用move函數(shù),因此一定是右值厨疙。
通過上面的例子我想你應(yīng)該已經(jīng)清楚forward的作用是什么了吧洲守?
forward實現(xiàn)原理
要分析forward實現(xiàn)原理,我們首先來看一下forward代碼實現(xiàn)。由于我們之前已經(jīng)有了分析std::move的基礎(chǔ)梗醇,所以再來看forward代碼應(yīng)該不會太困難知允。
template <typename T>
T&& forward(typename std::remove_reference<T>::type& param)
{
return static_cast<T&&>(param);
}
template <typename T>
T&& forward(typename std::remove_reference<T>::type&& param)
{
return static_cast<T&&>(param);
}
forward實現(xiàn)了兩個模板函數(shù),一個接收左值叙谨,另一個接收右值温鸽。在上面有代碼中:
typename std::remove_reference<T>::type
的含義我們在分析std::move時已經(jīng)向你做了說細的說明,其含義就是獲得去掉引用的參數(shù)類型手负。所以上面的兩上模板函數(shù)中涤垫,第一個是左值引用模板函數(shù),第二個是右值引用模板函數(shù)竟终。
緊接著std::forward模板函數(shù)對傳入的參數(shù)進行強制類型轉(zhuǎn)換蝠猬,轉(zhuǎn)換的目標(biāo)類型符合引用折疊規(guī)則,因此左值參數(shù)最終轉(zhuǎn)換后仍為左值统捶,右值參數(shù)最終轉(zhuǎn)成右值榆芦。
小結(jié)
本文我們首先通一個小例子向你介紹了std::forward的作用為“完美轉(zhuǎn)發(fā)”,也就是不改變原值的屬性瘾境。接著我?guī)惴治隽藄td::forward的原碼實現(xiàn)歧杏,如果你看過我之前對std::move的分析文章,相信你在閱讀std:forward的代碼實現(xiàn)時不會遇到什么困難