簡體   English   中英

為什么`std::make_tuple` 需要移動語義?

[英]Why does `std::make_tuple` require move semantics?

我認為通過std::make_tuple創建std::tuple需要右值引用參數(類型T&& )是一個非常有意識的設計決定。

但是,這意味着對象類型的移動語義(std::move 只不過是對T&& ,而且我對構建始終需要的std::tuple不太滿意。

int x = 7, y = 5;
std::tuple<int, int> fraction = make_tuple<int, int>( x, y ); // fails

關於上述,編譯器說:

錯誤 C2664:“std::tuple<int,int> std::make_tuple<int,int>(int &&,int &&)”:無法將參數 1 從“int”轉換為“int &&”

消息:您不能將左值綁定到右值引用

如果不使用make_tuple則可以make_tuple值創建std::tuple沒問題:

std::tuple<int, int> fraction = { x, y }; // ok

我的問題是,這是為什么?

std::make_tuple沒有對T進行右值引用,這與它看起來的相反; 它需要對T ( T&& ) 的通用引用。 如果通用參考對你來說是新的,讓我解釋一下。

make_tuple的定義或多或少是這樣的:

template<typename... Ts>
std::tuple<Ts...> make_tuple(Ts&&... ts){ 
    // ... 
}

但出於解釋的目的,我將像這樣引用make_tuple

template<typename T>
std::tuple<T> make_tuple(T&& t){ 
    // ... 
}

使用類型推導,當make_tuple傳遞一個右值(假設是int&& )時,為T推導出的類型是int ,因為 make_tuple 接受一個 T&& 並且它傳遞了一個右值。 make_tuple的定義(推導出T )現在看起來像這樣:

std::tuple<int> make_tuple(int&& t){ 
    // ... 
}

這就是事情變得令人困惑的地方:如果make_tuple被傳遞了一個左值int ,那么T應該推導出什么? 編譯器將T推導出為int&並使用稱為引用折疊的東西。

引用折疊基本上表明,如果編譯器形成對引用的引用,並且其中一個是左值,則生成的引用是左值。 否則,它是一個右值引用。

make_tuple的定義(推導出T )現在看起來像這樣:

std::tuple<int&> make_tuple(int& && t){ 
    // ... 
}

其中崩潰為:

std::tuple<int&> make_tuple(int& t){ 
    // ... 
}

所以,回到你失敗的例子:

std::tuple<int, int> fraction = make_tuple<int, int>( x, y );

讓我們看看make_tuple是什么樣的:

// since you explicitly called make_tuple<int,int>(), then no deduction occurs
std::tuple<int,int> make_tuple(int&& t1, int&& t2){ // Error! rvalue reference cannot bind to lvalue
    // ... 
}

現在很清楚為什么您的示例不起作用。 由於沒有發生參考折疊,因此T&&保持int&&

您的代碼的修訂版應如下所示:

auto fraction = std::make_tuple(x,y);

我希望我解釋得很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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