Jak wywołać odpowiedniego konstruktora typu szablonu?

21

Jak w poniższym kodzie mogę sprawić, by linia z komentarzem działała tak samo, jak linia tuż nad nią?

Chciałbym, aby był to ogólny kod, który wywołuje odpowiedniego konstruktora szablonu 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;
}
nikt wyjątkowy
źródło

Odpowiedzi:

14

Użyj bezpośredniej inicjalizacji:

Class<std::string> b("abc");
dranjohn
źródło
17

Użyj inicjowanej listy (lub jednolitej inicjacji), aby zainicjować instancję Class.

Class<std::string> a{ std::string("abc") };  // works
Class<std::string> b{ "abc" };               // also works
JeJo
źródło
13
Class<std::string> b = "abc";

jest inicjalizacja kopii . To nie działa, ponieważ wymagałoby dwóch konwersji zdefiniowanych przez użytkownika:

  • od const char*celu std::string,
  • od std::stringdo Class<std::string>.

Ale co najwyżej jeden jest dozwolony.

Kiedy piszesz

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

korzystasz z bezpośredniej inicjalizacji . Działa, ponieważ teraz używana jest tylko jedna konwersja zdefiniowana przez użytkownika:

  • od const char*do std::string.
Evg
źródło
0

Jeśli możesz to zmienić Class, możesz dodać konstruktora konwertującego szablony. Wtedy będziesz mógł skompilować skomentowany wiersz, jak napisano w twoim przykładzie. Należy jednak pamiętać, że generalnie nie zaleca się korzystania z niejawnych konwersji bez uzasadnionego powodu, ponieważ mogą one powodować trudne do wykrycia błędy (por. Podstawowe wytyczne 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;
}

Jeśli możesz użyć C ++ 14, możesz użyć std::literals::string_literals::operator""skonstruktora konwertującego i usunąć go. Wtedy twoja linia wyglądałaby tak:

using namespace std::literals;

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

Kod na żywo tutaj .

florestan
źródło