[英]Usage of std::forward vs std::move
我總是讀到std::forward
僅用於模板參數。 然而,我問自己為什么。 請參閱以下示例:
void ImageView::setImage(const Image& image){
_image = image;
}
void ImageView::setImage(Image&& image){
_image = std::move(image);
}
這是兩個基本相同的功能; 一個采用左值參考,另一個采用右值參考。 現在,我想既然std::forward
應該返回一個左值引用,如果參數是一個左值引用,如果參數是一個 r 值引用,那么這段代碼可以簡化為這樣的:
void ImageView::setImage(Image&& image){
_image = std::forward(image);
}
這有點類似於 cplusplus.com 提到的std::forward
示例(只是沒有任何模板參數)。 我只想知道,這是否正確,如果不正確,為什么。
我也在問自己到底有什么區別
void ImageView::setImage(Image& image){
_image = std::forward(image);
}
如果不明確指定其模板參數,則不能使用std::forward
。 它有意用於非推導的上下文中。
要理解這一點,您需要真正了解轉發引用( T&&
為推導的T
)如何在內部工作,而不是將它們揮之不去,因為“這很神奇”。 讓我們來看看。
template <class T>
void foo(T &&t)
{
bar(std::forward<T>(t));
}
假設我們像這樣調用foo
:
foo(42);
42
是一個int
類型的右值。T
被推導為int
。bar
的調用使用int
作為std::forward
的模板參數。std::forward<U>
的返回類型為U &&
(在本例中為int &&
),因此t
作為右值轉發。 現在,讓我們像這樣調用foo
:
int i = 42;
foo(i);
i
是int
類型的左值。V
被用於推斷T
在類型的參數T &&
, V &
用於扣除。 因此,在我們的例子中, T
被推導出為int &
。 因此,我們指定int &
作為std::forward
的模板參數。 因此,它的返回類型將是“ int & &&
”,它會折疊為int &
。 這是一個左值,所以i
被作為左值轉發。
概括
為什么這適用於模板是當您執行std::forward<T>
, T
有時是引用(當原始是左值時),有時不是(當原始是右值時)。 因此, std::forward
將視情況轉換為左值或右值引用。
您無法在非模板版本中准確地進行此工作,因為您將只有一種類型可用。 更不用說setImage(Image&& image)
根本不接受左值這一事實——左值不能綁定到右值引用。
我建議閱讀Scott Meyers 的“Effective Modern C++”,特別是:
std::move
和std::forward
。從純粹的技術角度來看,答案是肯定的:
std::forward
可以做到這一切。std::move
不是必需的。 當然,這兩個函數都不是真正必要的,因為我們可以在任何地方編寫強制轉換,但我希望我們同意這會很糟糕。std::move
的吸引力在於方便、減少出錯的可能性和更清晰。
此函數接受右值,不能接受左值。
void ImageView::setImage(Image&& image){
_image = std::forward(image); // error
_image = std::move(image); // conventional
_image = std::forward<Image>(image); // unconventional
}
首先注意std::move
只需要一個函數參數,而std::forward
需要一個函數參數和一個模板類型參數。
該函數接受所有並進行完美轉發。
template <typename T> void ImageView::setImage(T&& image){
_image = std::forward<T>(image);
}
您必須在std::forward
指定模板類型。
在這種情況下, Image&& image
始終是一個右值引用,而std::forward<Image>
將始終移動,因此您不妨使用std::move
。
您接受 r 值引用的函數不能接受左值,因此它不等同於前兩個函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.