簡體   English   中英

std::forward 與 std::move 的使用

[英]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);
  • iint類型的左值。
  • 因為完美轉發的特殊規則,當類型的左值的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++”,特別是:

  • 第 23 條:理解std::movestd::forward
  • 第 24 條:區分右值引用的通用引用。

從純粹的技術角度來看,答案是肯定的: 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM