2012-06-14 13 views
8

En el siguiente código, el constructor variadic se llama dos veces. ¿Cómo puedo hacer que se llame al constructor de copia en lugar de la versión de argumento único del constructor variadic cuando corresponda?¿Cómo puedo obtener el constructor de copia llamado sobre un constructor 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. 
} 

Respuesta

9

En realidad, esto no tiene nada que ver con el hecho de que el constructor es variadic. La siguiente clase con una plantilla constructor no variadic presenta el mismo comportamiento:

struct Foo 
{ 
    Foo() { } 

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

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

}; 

El problema es que la plantilla constructor es una mejor coincidencia. Para llamar al constructor de copia, se requiere una conversión de calificación para vincular el valor l no const f1 al const Foo& (se debe agregar la calificación const).

Para llamar a la plantilla constructor, no se requieren conversiones: T se puede deducir a Foo&, que tras el colapso de referencia (Foo& && ->Foo&), da el parámetro x tipo Foo&.

Puede solucionar esto proporcionando un constructor de segunda copia que tenga un parámetro de referencia l-valor no const Foo&.

+1

Hay algo más, es decir, colapso de referencia (¿cómo se llamó?), Es decir 'T &&&' => 'T &' porque de lo contrario un lvalue ('f1') no podría enlazarse a' T && '. –

4

sólo proporciona una sobrecarga de coincidencia exacta, es decir, uno con un no constFoo&, además del constructor de copia convencional. A continuación, puede delegar la llamada a través de una conversión explícita:

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