2011-11-25 17 views
6

Ho alcune difficoltà con l'inoltro perfetto.Inoltro perfetto e std :: tupla (o altra classe di modelli)

Ecco il mio attuale livello di comprensione: modello di colla + riferimento di rvalue + std :: forward e una modalità magica speciale attivata quando le regole di deduzione del modello non hanno lo stesso significato del solito, ma sono predisposte per consentire un inoltro perfetto. Esempio:

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

Ma cosa succede se T è in realtà una classe basata su modelli? Ad esempio, come posso perfezionare una std :: tuple? Se si utilizza un T & & come aboce, ho perso tutte le informazioni sul tipo degli oggetti contenuti nella tupla.
Tuttavia il seguente codice non può funzionare:

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); 
} 

Ultima istantanea gcc dice:

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

Così chiaramente, siamo ancora nel caso generale, non modello in cui lvalue non può legarsi per fare riferimento al valore. "Modalità forwading perfetto" non è attiva

così ho cercato di essere subdolo e superare il mio tuple come modello modello:

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...>(); 
} 

Ma ho ancora ottenere lo stesso errore.

+0

Non puoi semplicemente chiamare std :: forward senza specificare il tipo (poiché è una funzione di modello e può utilizzare la deduzione)? 'std :: forward (t)' – SoapBox

risposta

3

Perfetto inoltro funziona solo se il tipo di parametro è un tipo di modello per la funzione, quindi l'unico modo per ottenere l'inoltro perfetto è come nel vostro primo esempio:

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

I lavori di cui sopra, perché è un caso speciale in cui T viene dedotto come SomeType& o SomeType&&.

Questo, tuttavia, non significa che le informazioni sul tipo per gli elementi di tupla siano perse per sempre. È ancora recuperabile (anche se non penso che sia possibile digitare un pacchetto modello variadic). Ad esempio, si può ancora chiamare use_args_types_for_something_else come questo:

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(); 
} 

Potrebbe non esserci buona soluzione generale, però, ma si spera che tali situazioni sono rare. (Ad esempio, in questo particolare esempio, potrebbe essere più semplice sovraccaricare outer.)

+0

Grazie per la tua risposta gentile e precisa. Quindi, per quanto riguarda l'inoltro perfetto in C++ 11, mi sento ancora un po 'inquietante che si possa contare così tanto su questo strano combo "template + rref + std :: forward". Crea un punto minuscolo in cui le regole generali (come "i riferimenti di valore valgono SOLO in rvalue") non si applicano più. Mi chiedo se alcune sintassi speciali per l'inoltro perfetto non sarebbero state migliori per C++ 11. Ad ogni modo, è vero che una soluzione alternativa in questo caso non è un grosso problema dato che è ancora possibile fare due overload per 'outer', uno con const ref e uno con rref per emulare PF. –

Problemi correlati