2011-12-20 14 views
10

Supponiamo che io ho due struct s:Perfetto inoltro di un membro di oggetto

struct X {}; 
struct Y { X x; } 

Ho funzioni:

void f(X&); 
void f(X&&); 

Come faccio a scrivere una funzione g() che prende Y& o Y&& ma perfetta inoltro X& oppure X&& a f(), rispettivamente:

template <typename T> 
void g(T&& t) { 
    if (is_lvalue_reference<T>::value) { 
    f(t.x); 
    } else { 
    f(move(t.x)); 
    } 
} 

Il codice sopra riportato illustra la mia intenzione ma non è molto scalabile in quanto il numero di parametri aumenta. C'è un modo per farlo funzionare per l'inoltro perfetto e renderlo scalabile?

+0

Credo che cambiare 'is_lvalue_reference :: value' a' is_lvalue_reference (t))> :: value' avrà la semantica desiderata, ma penso che la tua semantica desiderata sia discutibile ... – ildjarn

+0

(Scusa per la risposta pasticciata.) Direi che il motivo per cui non scala è perché il design è discutibile per cominciare. Che cosa significa "spostare" un subobject? In quale stato questo lascia l'oggetto principale? Anche se ci fosse un modo semplice per scrivere questo, sembra codice scarsamente strutturato ... –

risposta

15
template <typename T> 
void g(T&& t) { 
    f(std::forward<T>(t).x); 
} 
+1

mi sembra buono http://ideone.com/Edf4o –

+0

Molto più bella soluzione, ma perché funziona esattamente? – Pubby

+0

@Pubby perché 'rvalue.foo' è un valore. Posso pensare al motivo per cui può avere senso (se il contenitore ha una vita breve ed è un valore rvalore, anche l'oggetto contenuto condivide tale proprietà), ma non ho familiarità con le filosofie e non conosco la logica, quindi non posso dire nulla al riguardo –

3

penso che questo funzionerà, anche se non sono sicuro:

template<class T, class M> 
struct mforward { 
    using type = M&&; 
}; 
template<class T, class M> 
struct mforward<T&, M> { 
    using type = M&; 
}; 

template <typename T> 
void g(T&& t) { 
    f(std::forward<typename mforward<T, decltype(t.x)>::type>(t.x)); 
} 
+2

+1 Ho dovuto risolvere quasi questo problema esatto in libC++. La soluzione che ho trovato sembrava molto simile a quella di Pubby. Non solo volevo "applicare" la l/r-valueness di 'T' a' M', volevo anche applicare le qualifiche cv di 'T' a' M'. E ho trovato applicazioni per questo oltre i membri dei dati. Per i curiosi, l'ho chiamato '__apply_cv' ed è un codice open source su: http://libcxx.llvm.org/ –

+0

@Howard vedere la mia risposta per un'alternativa. O mi manca qualcosa? –

+0

Anche @Howard che parla della qualifica di cv mi fa pensare a un difetto di questa risposta. 'decltype (t.x)' fornisce solo il tipo dichiarato di 'x'. Se 'T' è' const', ma 'x' è stato dichiarato come' int a', il tuo forward proverà ad inoltrare le cose come 'int &'/'int &&'. Dovresti dire qualcosa come 'typename remove_reference :: type' per prendere in considerazione la costanza di' t' too. Ciò tiene anche in considerazione i membri 'mutabili', ma non so quale mossa significhi filosoficamente a un membro mutabile di un oggetto altrimenti' const'. –

Problemi correlati