2011-11-25 62 views
6

完美轉發有一些困難。完美轉發和std ::元組(或其他模板類)

這裏是我目前的理解水平:glue Template + rvalue reference + std :: forward以及一個特殊的魔法模式,在模板扣除規則與通常意義不同的情況下被激活,但是被製作爲允許完美轉發。例如:

template <typename T> 
void outer(T&& t) 
{ 
    inner(std::forward<T>(t)); // perfect forwarding activated 
} 

但是如果T實際上是一個模板類,會發生什麼?例如,我如何完善一個std ::元組?如果使用T & &作爲aboce,我將丟失包含在元組中的對象的所有類型信息。
但是下面的代碼不能工作:

template <typename... Args> 
void outer(std::tuple<Args...>&& t) 
{ 
    inner(std::forward<std::tuple<Args...>>(t)); 
    use_args_types_for_something_else<Args...>(); // I need to have Args available 
} 

int main() 
{ 
    std::tuple<int, double, float> t(4, 5.0, 4.0f); 
    outer(t); 
} 

末GCC快照說:

error: cannot bind 'std::tuple<int, double, float> lvalue to 
std::tuple<int, double, float>&& 

所以很明顯,我們仍然在一般情況下,非模板情況下左值不能綁定給右值參考。 「完美forwading模式」未激活

於是,我就偷偷摸摸,並通過我的元組爲模板,模板:

template < 
    typename... Args 
    template <typename...> class T 
> 
void outer(T<Args...>&& t) 
{ 
    inner(std::forward<T<Args...>>(t)); 
    use_args_type_for_something_else<Args...>(); 
} 

但我仍然得到同樣的錯誤。

+0

難道你不能只調用std :: forward而沒有指定類型(因爲它是一個模板函數,可以使用演繹)? 'std :: forward(t)' – SoapBox

回答

3

完美轉發工作只有在參數的類型是功能的模板類型,因此要實現完美轉發的唯一途徑就是像你第一個例子:

template <typename T> 
void outer(T&& t) 
{ 
    inner(std::forward<T>(t)); // perfect forwarding activated 
} 

以上的作品,因爲它是T推導爲SomeType&SomeType&&的特殊情況。

但是,這並不意味着元組元素的類型信息會丟失。它仍然是可檢索的(儘管我不認爲你可以鍵入一個可變模板包)。例如,你仍然可以調用use_args_types_for_something_else這樣的:

template <class T> 
struct call_uses_args; 

template <class ...Args> 
struct call_uses_args<std::tuple<Args...>> 
{ 
    void call() const { use_args_types_for_something_else<Args...>(); } 
}; 

template <typename TupleT> 
void outer(TupleT&& t) 
{ 
    inner(std::forward<TupleT>(t)); 
    call_uses_args<typename std::remove_reference<TupleT>::type>().call(); 
} 

有可能是沒有好的解決方法,雖然,但希望這種情況並不多見。 (例如,在這個特定的例子中,它可能更簡單,只是過載outer。)

+0

謝謝你的精確和精確的答案。所以關於在C++ 11中的完美轉發,我仍然感到有點不安,它非常依賴這個奇怪的組合「template + rref + std :: forward」。它創建了一個小地方,其中的一般規則(比如「右值引用只能綁定右值」)不再適用。我想知道對於完美轉發而言,一些特殊的語法對於C++ 11來說會不會更好。無論如何,在這種情況下,解決方法並不是什麼大事,因爲它仍然有可能對'outer'進行兩次重載,一次使用const ref,另一次使用rref來模擬PF。 –