Como chamar o construtor certo de um tipo de modelo?

21

No código a seguir, como posso fazer com que a linha comentada funcione da mesma maneira que a linha acima dela?

Gostaria de torná-lo um código genérico, que chama o construtor adequado de um modelo 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;
}
ninguém especial
fonte

Respostas:

14

Use inicialização direta:

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

Use braced-init-list (ou iniciação uniforme) para iniciar a instância de Class.

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

é inicialização de cópia . Não funciona porque envolveria duas conversões definidas pelo usuário:

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

Mas no máximo um é permitido.

Quando você escreve

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

você usa inicialização direta . Funciona porque agora apenas uma conversão definida pelo usuário é usada:

  • de const char*para std::string.
Evg
fonte
0

Se você puder alterar o seu Class, poderá adicionar um construtor de conversão modelado. Em seguida, você poderá compilar a linha comentada, conforme escrito em seu exemplo. No entanto, geralmente não é recomendável usar conversões implícitas sem uma razão decente, pois elas podem resultar em erros difíceis de detectar (consulte as diretrizes principais do 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;
}

Se você pode usar o C ++ 14, pode usar o std::literals::string_literals::operator""se remover o construtor de conversão. Então, sua linha ficaria assim:

using namespace std::literals;

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

Código ao vivo aqui .

Florestan
fonte