¿Cómo llamar al constructor correcto de un tipo de plantilla?

21

En el siguiente código, ¿cómo puedo hacer que la línea comentada funcione de la misma manera que la línea justo encima de ella?

Me gustaría convertirlo en un código genérico, que llame al constructor adecuado de una plantilla Type.

#include <string>
#include <iostream>

template <typename Type>
struct Class
{
    Type data;
    Class(Type data) : data(data) { }
};

int main()
{
    Class<std::string> a = std::string("abc");
    // Class<std::string> b = "abc";
    std::cout << a.data << std::endl;
    return 0;
}
nadie especial
fuente

Respuestas:

14

Usar inicialización directa:

Class<std::string> b("abc");
dranjohn
fuente
17

Use braced-init-list (o uniform-inittion) para iniciar la instancia de Class.

Class<std::string> a{ std::string("abc") };  // works
Class<std::string> b{ "abc" };               // also works
JeJo
fuente
13
Class<std::string> b = "abc";

es la inicialización de copia . No funciona porque implicaría dos conversiones definidas por el usuario:

  • a partir const char*de std::string,
  • de std::stringa Class<std::string>.

Pero a lo más uno está permitido.

Cuando escribes

Class<std::string> b("abc");
// or
Class<std::string> b{"abc"};

Utiliza la inicialización directa . Funciona porque ahora solo se usa una conversión definida por el usuario:

  • de const char*a std::string.
Evg
fuente
0

Si puede cambiar su Class, puede agregar un constructor de conversión con plantilla. Entonces podrá compilar la línea comentada como está escrita en su ejemplo. Sin embargo, tenga en cuenta que, en general, no se recomienda utilizar conversiones implícitas sin una razón decente, ya que pueden provocar errores difíciles de detectar ( consulte las Directrices básicas de C ++ ).

#include <string>
#include <iostream>

template <typename Type>
struct Class
{
    Type data;
    Class(Type data) : data(data) { }

    template<typename Other>
    Class(Other other_data) : data(other_data) {}
};


int main()
{
    Class<std::string> a = std::string("abc");
    Class<std::string> b = "abc";
    Class<std::string> c = a;

    std::cout << b.data << std::endl;
    return 0;
}

Si puede usar C ++ 14, puede usar std::literals::string_literals::operator""sy eliminar el constructor de conversión. Entonces, su línea se vería así:

using namespace std::literals;

Class<std::string> b = "abc"s;

Código en vivo aquí .

Florestan
fuente