[英]Why does std::make_tuple turn std::reference_wrapper<X> arguments into X&?
[英]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.