Comment appeler le bon constructeur d'un type de modèle?

21

Dans le code suivant, comment puis-je faire fonctionner la ligne commentée de la même manière que la ligne juste au-dessus?

Je voudrais en faire un code générique, qui appelle le constructeur approprié d'un modèle 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;
}
personne de spécial
la source

Réponses:

14

Utilisez l'initialisation directe:

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

Utilisez braced-init-list (ou uniform-initiation) pour initialiser l'instance de Class.

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

est la copie-initialisation . Cela ne fonctionne pas, car cela impliquerait deux conversions définies par l'utilisateur:

  • de const char*à std::string,
  • du std::stringau Class<std::string>.

Mais tout au plus est autorisé.

Quand tu écris

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

vous utilisez l'initialisation directe . Cela fonctionne car maintenant une seule conversion définie par l'utilisateur est utilisée:

  • du const char*au std::string.
Evg
la source
0

Si vous pouvez modifier votre Class, vous pouvez ajouter un constructeur de conversion basé sur des modèles. Vous pourrez alors compiler la ligne commentée comme écrit dans votre exemple. Notez cependant qu'il n'est généralement pas recommandé d'utiliser des conversions implicites sans raison décente car elles peuvent entraîner des bogues difficiles à repérer (cf. les lignes directrices de base 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 vous pouvez utiliser C ++ 14, vous pouvez utiliser le std::literals::string_literals::operator""set supprimer le constructeur de conversion. Ensuite, votre ligne ressemblerait à ceci:

using namespace std::literals;

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

Code en direct ici .

florestan
la source