2012-06-14 4 views
8

Nel seguente codice, il costruttore variadic viene chiamato due volte. Come posso richiamare il costruttore della copia anziché la versione a singolo argomento del costruttore variadic quando appropriato?Come posso richiamare il costruttore della copia su un costruttore variadic?

#include <iostream> 

struct Foo 
{ 
    Foo(const Foo &) 
    { 
     std::cout << "copy constructor\n"; 
    } 

    template<typename... Args> 
    Foo(Args&&... args) 
    { 
     std::cout << "variadic constructor\n"; 
    } 

    std::string message; 
}; 

int main() 
{ 
    Foo f1; 
    Foo f2(f1); // this calls the variadic constructor, but I want the copy constructor. 
} 

risposta

9

Questo in realtà non ha nulla a che fare con il fatto che il costruttore è variadic. La seguente classe con un modello del costruttore non variadic presenta lo stesso comportamento:

struct Foo 
{ 
    Foo() { } 

    Foo(const Foo& x) 
    { 
     std::cout << "copy constructor\n"; 
    } 

    template <typename T> 
    Foo(T&& x) 
    { 
     std::cout << "template constructor\n"; 
    } 

}; 

Il problema è che il modello costruttore è una migliore corrispondenza. Per chiamare il costruttore di copie, è necessaria una conversione di qualifica per associare il valore non costante f1 a const Foo& (la qualifica const deve essere aggiunta).

Per chiamare il modello costruttore, non sono necessarie conversioni: T può dedurre a Foo&, che, dopo il collasso di riferimento (Foo& && ->Foo&), dà il parametro x tipo Foo&.

È possibile aggirare il problema fornendo un secondo costruttore di copia che ha un parametro di riferimento di l valore non costante Foo&.

+1

C'è un po 'di più ad esso, vale a dire il collasso di riferimento (come si chiamava?), Cioè "T &&&' => 'T &' perché altrimenti un lvalue ('f1') non poteva legarsi a' T &&'. –

4

Basta fornire un sovraccarico corrispondenza esatta, vale a dire uno con un non constFoo&, oltre al costruttore di copia convenzionale. Poi si può delegare la chiamata tramite un cast esplicito:

Foo(Foo& other) : Foo(static_cast<Foo const&>(other)) { }