C++的完美轉發只能針對形如T &&的形參嗎?
例如對於函數
template& class T, typename U&>void foo(T& val){
// ....}我用的g++-4.9隻能匹配右值,無法匹配左值。這樣的話該怎樣實現完美轉發,我不想再寫一次這個函數。
做這種事情的關鍵是你要明白(T) == T,這就是為什麼別人的完美轉發都能接受左值引用,而你的不行。T&無法被推導成X,你把它改掉就好了。至於如何保證參數一定是T&,用一句static_assert就可以搞定了。
我猜題主的需求是在foo中要使用到T和U的信息,那麼可以這樣寫:
// 一個利用特化提取類型的Helper類
template &
struct Decompose;
template & class T, typename U&>
struct Decompose&
template &
using t = T&
using u = U;
};
// 這裡先觸發類型推導
template &
void foo(TU val) {
// 然後用std::decay把TU的const/volatile/reference修飾去掉,並填入Helper類。
using D = Decompose&
/*
// 使用方法:
// U可以直接提取出來
using U = typename D::u;
U *u; // OK
// T(似乎..)不能提取出來,不過你可以在需要的時候這麼用(將int替換成你需要的類型):
using OtherInstanceOfTemplateT = typename D::template t&
*/
}
推薦《Effective Modern C++》,上面講得很清楚
C++11中,T這種語法形式有兩種意思:
- 右值引用(Rvalue reference),只能綁定右值
- 萬能引用(Universal reference),既能綁定右值,又能綁定左值
只有發生類型推導的時候,T才表示萬能引用。
template&
void Foo(T arg); // 發生類型推導,T表示萬能引用
auto i = 42; // 發生類型推導,T表示萬能引用
void Foo(int arg); // 沒有類型推導,int表示右值引用,只能綁定右值
int rRef = 3; // 沒有類型推導,int表示右值引用,只能綁定右值
題主的那個特化的模版函數是沒有類型推導的,只能接受右值。如果作用域內沒有其他重載的接受左值的foo函數,編譯器就會報錯啦。回到題主的問題,雖然右值引用不能隱式綁定左值,但如果你硬要傳一個左值的話,可以顯式轉換實參,這樣調用:
foo(std::move(lvalueArg));
// std::move無條件地將其參數轉為右值
// 這樣調用的後果是,lvalueArg將處於destructable的狀態,它的值可能不再有效。
推薦閱讀:
※現在C++開發是不是都遵守C++11標準,Linux下的多線程編程是優先考慮C++11的線程庫,還是用系統線程API封裝?
※大學C++應該怎麼學?
※用很厚的教材學編程的時候,該如何一邊攤開書一邊敲代碼?
※如何讓編譯器在預處理時在一個項目中的某些指定文件中每一個函數定義前插入一個宏?
※C++ 03和C++11的vector在調用元素的構造函數時有什麼區別?