2015-01-29 2 views
5

Considerate:Implicitamente chiamando costruttore di copia

struct Foo 
{ 
    Foo(std::string str) {} 
}; 

struct Bar 
{ 
    Bar(Foo f) {} 
}; 

int main(int argc, char* argv[]) 
{ 
    Foo f("test"); 

    Bar b1(f); 
    Bar b2(std::string("test")); 
    Bar b3("test"); 

    return 0; 
} 

Questo non riesce a compilare sulla dichiarazione di b3 ('non in grado di convertire l'argomento 1 da 'const char [5]' a 'Foo''). Il che ha senso, perché non esiste un modo diretto per convertire il const-char in un Foo. Tuttavia, c'è un modo per convertire il const char in una std :: string, e quindi usarlo per costruire un Foo (che è ciò che sta accadendo in b1 e b2), ed è quello che voglio perché rende l'API più carina da usare (non dover istanziare un Foo o uno std :: string esplicitamente ogni volta).

Quindi la mia domanda è: esiste un modo per consentire al compilatore di chiamare implicitamente il costruttore di copie Foo (std :: string)? In altre parole, c'è un modo per fare una dichiarazione come quella di b3, lasciare che sia uguale a b2 e senza dichiarare un costruttore di copia const char * per Foo? (che l'ultima cosa è la via ovvia ma il mio codice reale non è ovviamente così semplice, e preferirei non dover aggiungere costruttori di copia const char * e gestire tutte le altre inizializzazioni nei costruttori correttamente e tenerlo in sincronizzazione con il costruttore std :: string copy).

+6

Una sequenza di conversione implicita può contenere solo una conversione definita dall'utente. Stai chiedendo due ('const char *' a 'std :: string', quindi' std :: string' a 'Foo'). Un modo per andare sarebbe quello di aggiungere un sovraccarico del costruttore 'Foo' prendendo' const char * '. –

+0

Nitpick: nessuno dei costruttori menzionati è un costruttore * copy *, sono solo costruttori. – molbdnilo

+0

Grazie, "sequenza di conversione implicita" è la stringa magica che stavo cercando. In effetti è impossibile fare ciò che volevo, dovrò usare un costruttore extra. – Roel

risposta

1

quello di cambiare questo:

struct Bar 
{ 
    Bar(Foo f) {} 
}; 

a

struct Bar 
{ 
    Bar(Foo f) {} 
    Bar(std::string f) {} 
}; 

utilizzando il polimorfismo ...

+5

Il polimorfismo (nel solito senso di OOP) ha poco a che fare con questo, è semplicemente un sovraccarico. – Puppy

+0

Grazie, ma questo soffre (nel mio caso) degli stessi problemi di manutenzione che stavo cercando di evitare non avendo il costruttore const char *. Sembra che dovrò fare un costruttore aggiuntivo per farlo funzionare. – Roel

8

Se C++ 11 è accettabile, si potrebbe aggiungere un costruttore delegando ad Foo che prende un const char* e chiama semplicemente l'altro costruttore:

struct Foo 
{ 
    Foo(std::string str) {} 
    Foo(const char* str) : Foo(std::string(str)) {} 
}; 

In alternativa, è possibile utilizzare C++ 14 di std::string letterale:

using namespace::std::string_literals; 
Bar b3("test"s); 

Si potrebbe anche emulare un costruttore di delegare avendo entrambi i costruttori chiamano una funzione separata:

struct Foo 
{ 
    Foo(std::string str) { init(str); } 
    Foo(const char* str) { init(str); } 
    void init(std::string str) {} 
}; 

L'aspetto negativo della sopra è necessario riflettere attentamente su tutto ciò che si stava facendo negli elenchi di inizializzazione che ora è necessario fare nel corpo di init.

+0

VS2013, non delegare i costruttori né std :: string letterale :( – Roel

+0

@Roel Che ne dici di emulare i costruttori deleganti come nella mia modifica? – TartanLlama

+1

Sì, è quello che finirò a fare suppongo.Lo svantaggio (come sono sicuro tu sai) è che i membri non saranno costruiti sul posto. Quale non sarà evidente o misurabile affatto nel mio codice in termini di velocità, ma si sente ancora leggermente icky;) – Roel

Problemi correlati