Wie rufe ich den richtigen Konstruktor eines Vorlagentyps auf?

21

Wie kann ich im folgenden Code dafür sorgen, dass die kommentierte Zeile genauso funktioniert wie die Zeile direkt darüber?

Ich möchte daraus einen generischen Code machen, der einen geeigneten Konstruktor einer Vorlage aufruft 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;
}
niemand besonderes
quelle

Antworten:

14

Verwenden Sie die direkte Initialisierung:

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

Verwenden Sie die Klammer-Init-Liste (oder die Uniform-Initiation), um die Instanz von zu initialisieren Class.

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

ist Kopierinitialisierung . Es funktioniert nicht, da zwei benutzerdefinierte Konvertierungen erforderlich wären:

  • von const char*bis std::string,
  • von std::stringbis Class<std::string>.

Aber höchstens einer ist erlaubt.

Wenn du schreibst

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

Sie verwenden die Direktinitialisierung . Es funktioniert, weil jetzt nur eine benutzerdefinierte Konvertierung verwendet wird:

  • von const char*bis std::string.
Evg
quelle
0

Wenn Sie Ihre ändern können Class, können Sie einen Konstruktor für die Konvertierung von Vorlagen hinzufügen. Dann können Sie die kommentierte Zeile wie in Ihrem Beispiel beschrieben kompilieren. Beachten Sie jedoch, dass es im Allgemeinen nicht empfohlen wird, implizite Konvertierungen ohne triftigen Grund zu verwenden, da dies zu schwer zu erkennenden Fehlern führen kann (siehe C ++ - Kernrichtlinien ).

#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;
}

Wenn Sie C ++ 14 verwenden können, können Sie std::literals::string_literals::operator""sden konvertierenden Konstruktor verwenden und entfernen. Dann würde Ihre Linie so aussehen:

using namespace std::literals;

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

Live-Code hier .

florestan
quelle