揭開std::move 轉換魔法的神秘面紗
當調用std::move() 時,令人費解的是觀察到引用的右值參數可以綁定到左值,通常限制左值附加到右值引用。深入研究 std::move() 的實現揭示了這個明顯悖論的關鍵。
剖析std::move() 實作
從精煉的開始std::move() 的版本:
template <typename T> typename remove_reference<T>::type&& move(T&& arg) { return static_cast<typename remove_reference<T>::type&&>(arg); }
案例1:呼叫move()與右值
當 move() 與右邊值一起使用時,例如暫時物件:
Object a = std::move(Object()); // Object() is temporary, hence prvalue
產生的範本實例化為:
remove_reference<Object>::type&& move(Object&& arg) { return static_cast<remove_reference<Object>::type&&>(arg); }
由於remove_reference將T&轉換為T或T&&轉換為T,而Object是一個普通值,所以最終的函數形態變為:
Object&& move(Object&& arg) { return static_cast<Object&&>(arg); }
強制轉換至關重要,因為命名的右值引用被視為左值。
情況2:使用左值呼叫move()
使用左值呼叫move() 時:
Object a; // a is an lvalue Object b = std::move(a);
產生的move () 實例化為:
remove_reference<Object&>::type&& move(Object& && arg) { return static_cast<remove_reference<Object&>::type&&>(arg); }
再,remove_reference將 Object& 轉換為 Object,產生:
Object&& move(Object& && arg) { return static_cast<Object&&>(arg); }
引用摺疊的本質
理解 Object& && 與其綁定左值的能力是關鍵解開謎團。 C 11 引入了引用折疊的特殊規則,其中規定:
Object & && = Object & Object & &&& = Object & Object && & = Object & Object && &&& = Object &&
因此,Object& && 實際上轉換為 Object&,一個可以輕鬆綁定到左值的典型左值引用。
結果函數
根據這些規則,最終函數變成:
Object&& move(Object& arg) { return static_cast<Object&&>(arg); }
鏡像右值的實例化,它將其參數轉換為右值引用,從而確保統一的行為。
remove_reference 的重要性
當檢查替代方案時,remove_reference的目的就變得顯而易見函數:
template <typename T> T&& wanna_be_move(T&& arg) { return static_cast<T&&>(arg); }
當用左值實例化時:
Object& && wanna_be_move(Object& && arg) { return static_cast<Object& &&&>(arg); }
應用引用折疊規則會顯示一個不可用的類似移動的函數,為左值參數傳回左值。罪魁禍首是缺少remove_reference,它阻礙了正確轉換為右值引用。
以上是當右邊值參考應該只綁定到右邊值時,std::move() 如何綁定到左值?的詳細內容。更多資訊請關注PHP中文網其他相關文章!