2016-01-19 12 views
6

Sto lavorando in un file che ha una determinata funzione con molti sovraccarichi, in questo modo:Il mio modello generico dovrebbe usare T o T &&?

inline X f(ScriptWrappable* impl, Y y, Z z) { ... } 
inline X f(Node* impl, Y y, Z z) { ... } 
inline X f(RawPtr<T> impl, Y y, Z z) { ... } 
inline X f(const RefPtr<T>& impl, Y y, Z z) { ... } 
inline X f(ScriptWrappable* impl, Y y, Z z) { ... } 
inline X f(const String& impl, Y y, Z z) { ... } 
inline X f(int64_t impl, Y y, Z z) { ... } 
template<typename T, size_t capacity> inline X f(const Vector<T, capacity>& impl, Y y, Z z) { ... } 

Sto cercando di aggiungere un nuovo sovraccarico che richiede solo un parametro, in questo modo:

template<typename T> inline X f(T impl, W w) { 
    return f(impl, w->getY(), w->getZ()); 
} 

Uso i modelli in modo che tutte le varianti sopra descritte funzionino automaticamente con la mia nuova versione a due parametri.

Tuttavia, durante la revisione del codice mi è stato chiesto, "È T&& migliore per evitare la copia?". Cioè, dovrei invece fare

template<typename T> inline X f(T&& impl, W w) { 
    return f(impl, w->getY(), w->getZ()); 
} 

Non so davvero la risposta a questa domanda. Pensavo di aver capito riferimenti universali, ma non mi è familiare quando sono una buona idea o no. Quali sarebbero le conseguenze nella mia situazione di scegliere l'una rispetto all'altra?

Se dovessi tirare a indovinare, direi che dal momento che i tipi originali che T può sostituire sono tutti semplici da copiare (primitive, riferimenti, o puntatori) T & & non darà molto beneficio. Ma sono ancora curioso se ad es. qualsiasi tipo potrebbe essere passato alla versione T & & che non è stato possibile passare alla versione T o viceversa.

+0

Se il chiamante vuole spostarsi, dovrebbe solo 'std :: move' l'argomento. Usando 'T && 'stai ** costringendolo ** a farlo. Usando solo "T" gli stai dando una scelta. –

+4

questo non è vero quando si utilizzano modelli nel contesto dedotto –

+0

Ah, non lo sapeva. Grazie per il chiarimento. –

risposta

8

si dovrebbe scrivere il funzione come questa:

template<typename T> inline X f(T&& impl, W w) { 
    return f(std::forward<T>(impl), w->getY(), w->getZ()); 
} 

Questo si chiama l'inoltro perfetto. Il tipo di impl sarà esattamente lo stesso come se avessi chiamato direttamente f. Sarà non necessariamente un riferimento di valore r.

+0

Grazie! Sembra che l'inoltro perfetto corrisponda meglio al mio intento. Sto ancora sperando di capire cosa succederebbe in modo diverso se avessi scelto le altre alternative, ma la ricerca di "forwarding perfetto" mi dà pagine come http://eli.thegreenplace.net/2014/perfect-forwarding-and-universal -ferenze-in-c/che sembrano aiutare. – Domenic

+0

Dai un'occhiata alla risposta di Richard Hodges. –

+0

@TobiasBrandt, a meno che f non sia inteso come proprietario di impl, perché non utilizzare const T &. –

3

La risposta è un po 'complessa perché richiede una certa comprensione delle regole del compilatore relative ai modelli.

Nella seguente dichiarazione:

template<class T> void func(T&& t); 

T viene valutata in dedotta contesto e di conseguenza saranno trattati dal compilatore sia come riferimento r-valore o un riferimento l-value, qualunque sia il caso. Accoppiato con l'uso di std::forward (nota: in questo caso nonstd::move) ciò si traduce in un perfetto inoltro ed è ottimamente efficiente.

Tuttavia, questo non è stato valutato in context dedotta:

template<class T> 
struct X { 
    void foo(T&& t); 
}; 

In questo caso, foo è infatti chiedere un riferimento r-value.

Né è questo contesto dedotto:

template<class T> 
void foo(std::vector<T>&& v); 

In questi due casi, è necessario utilizzare std::move.

+0

Non è la valutazione di 'T' in un contesto dedotto che lo rende un valore r o un riferimento di valore l. 'typedef int & T; typedef T && X;' non ha un contesto dedotto, tuttavia 'X' è di tipo' int & '. Sostituisci con 'typedef int T;' e 'X' diventa di tipo' int && '. Non c'è magia che coinvolga la deduzione implicata nel fare di "T &&" un riferimento di valore o di lvalue; questa è la regola del collasso di riferimento. Le regole di deduzione danno come risultato che 'T' in' T && 'viene dedotto in certi modi per consentire a dette regole di generare un riferimento di valore l o r, ma questa è una vera differenza. – Yakk

+0

Perdonami se ho la dicitura sbagliata. Qual è la forma corretta delle parole? –

+0

Coloro che possono, postare. Coloro che non possono, criticano i post di altri. :) La scelta delle parole necessarie per parlare della deduzione del tipo di modello dagli argomenti di funzione e dai riferimenti di inoltro è * difficile *. – Yakk

Problemi correlati