2011-09-12 17 views
7

Attualmente, uno dei miei modelli di classe giocattolo ha due costruttori che sembrano molto simili:combinazione di due costruttori che copiare e spostare

optional(const T& x) 
{ 
    construct(x); 
} 

optional(T&& x) 
{ 
    construct(std::move(x)); 
} 

li posso combinare in un unico modello costruttore, o sarà questo cambiamento la semantica in qualche modo ?

template<typename U> 
optional(U&& x) 
{ 
    construct(std::forward<U>(x)); 
} 
+0

qual è la vera carne del 'costrutto'? –

+0

@Alf: posizionamento brutto di nuove cose sulla memoria allineata :) – fredoverflow

risposta

2

cambia il modo tratti come std::is_constructible e std::is_convertible interagire con optional . Ad esempio dato:

class A {}; 

int main() 
{ 
    std::cout << std::is_constructible<optional<A>, int>::value << '\n'; 
}; 

tuo codice originale sarebbe stampare:

0 

Ma il nuovo codice sarà stampare:

1 

Se questo è indesiderabile, e si vuole ancora vai con il tuo nuovo codice, potresti enable_if per restringere lo U a tipi accettabili.

L'unico altro problema possibile che vedo è se T può essere un tipo di riferimento (ad esempio int&).In tal caso, il secondo costruttore del codice originale sembra sospetto in quanto passerebbe in un valore rval, e si potrebbe provare a associare tale valore a un riferimento a valore non costante (non si sa per certo). Se T non può mai essere un tipo di riferimento, non è necessario preoccuparsi di questo.

4

Un costruttore di modelli non sarà mai (considerato dal compilatore di essere) un costruttore di copia, mi dispiace.

+0

Erm, 'opzionale (const T &)' non è nemmeno un costruttore di copie, cosa stavo pensando? modificato – fredoverflow

+0

@Fred: in tal caso, è consigliabile utilizzare l'inoltro del costruttore C++ 11? se è ancora implementato dal compilatore. non so quali compilatori lo supportano, se ce ne sono. in alternativa, se non supportato, puoi usare una classe base artificiale. Inoltra il costruttore chiama alla classe base. –

+0

Oh, 'construct' non è un costruttore, è un modello di funzione membro. – fredoverflow

1

Oh, construct non è un costruttore, è un modello di funzione membro.

Allora forse la semantica è diversa. Il set di overload originale passa o un riferimento lvalue a const o un riferimento rvalue a non-const. La versione del modello può passare un riferimento lvalue a non -const. (Sto ignorando i riferimenti rvalue a const.)

In tutta probabilità se construct si sia dichiarato di accettare U&& (altrimenti il ​​sovraccarico precedente che sposta un T non avrebbe funzionato) e in questo caso dovrebbe affare con non -const lvalues, o è dichiarato di accettare U const& e in questo caso è innocuo.

0

Supponendo di avere almeno construct(const T& x) ed eventualmente l'aggiunta di construct(T&& x) definito, e il vostro oggetto di tipo U è convertibile ad un oggetto di tipo T, penso che si dovrebbe andare bene ...

  1. Una costante l-valore di riferimento di tipo U legherà construct(const T& x)
  2. a l-valore non costante riferimento di tipo U legherà construct(const T& x)
  3. a r-valore temporaneo di tipo U sarà associare a construct(T&& x) o construct(const T& x) se la versione di riferimento r-valore non è definito
  4. A r-valore costante riferimento di tipo U si legheranno al construct(const T& x)