2013-08-22 32 views
1

鑑於從「C++編程語言第四版」下面的函數模板:函數模板使用的std ::正向和右值

template <typename TT, typename A> 
unique_ptr<TT> make_unique(int i, A && a) 
{ 
     return unique_ptr<TT>{new TT{ i, std::forward<A>(a) }}; 
} 

我覺得很難理解,其實呢,

a肯定是一個右值,因此make_unique函數 似乎將其內容分配到堆上,並將該地址保存在unique_ptr中,因此我們不必擔心刪除它。但是,標準庫轉發函數做了什麼? (我猜這跟一個右值有關)我嘗試閱讀C++文檔,但我似乎沒有正確理解。 很想從更有經驗的C++程序員那裏得到一個很好的解釋。

謝謝!

回答

2

嗯...我敢肯定這是不是爲將來std::make_unique的一個變通的實施給予,但無論如何,函數功能是很容易理解的,但它需要你具有新的C++ 11功能的先驗知識。

template <typename TT, typename A> 
unique_ptr<TT> make_unique(int i, A && a) 
{ 
     return unique_ptr<TT>{new TT{ i, std::forward<A>(a) }}; 
} 

所有make_unique首先是函數模板,我真的希望你已經知道了,如下面將需要您有至少最基本的知識是什麼模板功能以及如何使用模板工作。

現在到非平凡的部分。 A && a有一個函數參數。具體而言,a是類型爲A&&的函數參數,其爲r-value reference。由於它的類型是模板類型參數,我們可以從調用者作爲參數傳遞給a的任何參數推導出它的類型。每當我們有r值參考和參數類型扣除,特殊扣除規則和參考摺疊踢腿,我們有一個所謂的「通用參考」這是完美的轉發功能特別有用。當我們有一個通用的參考文獻(在我們的例子中爲a)時,我們幾乎總是希望每當我們想要使用它們時都保留其原始的「l值」或「r值」。要有這種行爲,我們幾乎總是應該使用std::forwardstd::forward<A>(a))。通過使用std::forward,最初作爲l值傳遞的變量保持爲l值,並且最初作爲r值傳遞的變量仍然是r值。

在那之後,事情只是簡單的

return unique_ptr<TT>{new TT{ i, std::forward<A>(a) }}; 

注意使用括號。它使用C++ 11的uniform initialization調用構造函數的語法來代替使用括號。通過new TT{ i, std::forward<A>(a) },您可以動態分配帶有大括號內給定參數的TT類型的對象。使用unique_ptr<TT>{new TT{ i, std::forward<A>(a) }};,您將創建一個unique_ptr<TT>,其參數是動態分配返回的參數。現在,該函數返回unique_ptr<TT>對象。

1

由於模板參數推導和參考摺疊規則,您無法知道a是右值參考還是左值參考。 std::forward將參數傳遞給TT控制器,就像它傳遞給make_unique一樣。斯科特·邁耶斯稱A&& a universal reference,因爲它可以是一個左值ref或右值ref,取決於傳遞給make_unique的內容。

如果你通過一個右值Foomake_unique,std::forward傳遞一個右值引用。

如果您通過左值Foomake_unique,std::forward傳遞一個左值引用。

make_unique(1, Foo());   // make_unique(int, A&&) -> rvalue ref 
Foo f; 
make_unique(1, f);    // make_unique(int, A&&&) -> make_unique(int, A&) -> lvalue ref 
make_unique(1, std::move(f)); // make_unique(int, A&&&&) -> make_unique(int, A&&) -> rvalue ref 
相關問題