W oświeconym wieku 2016 roku, gdy mamy dwa nowe standardy od czasu zadania tego pytania i nowy tuż za rogiem, najważniejsze jest to, aby wiedzieć, że kompilatory obsługujące standard C ++ 17 skompilują kod tak, jak jest .
Odliczenie argumentów-szablonów dla szablonów klas w C ++ 17
Tutaj (dzięki uprzejmości redakcji przyjętej odpowiedzi Olzhasa Zhumabka) znajduje się artykuł szczegółowo opisujący odpowiednie zmiany w standardzie.
Rozwiązywanie problemów wynikających z innych odpowiedzi
Aktualnie najwyżej oceniana odpowiedź
Ta odpowiedź wskazuje, że „konstruktor kopiujący i operator=
” nie znałby prawidłowych specjalizacji szablonów.
To nonsens, ponieważ standardowy konstruktor kopiujący operator=
istnieje tylko dla znanego typu szablonu:
template <typename T>
class MyClass {
MyClass(const MyClass&) =default;
... etc...
};
// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm; // WHAT IS THIS?
*pm = m;
Oto, jak zauważył w komentarzach, nie ma żadnego powodu, aby MyClass *pm
być deklaracja prawny z lub bez nowej formy wnioskowania: MyClass
Nie jest typem (jest to szablon), więc to nie ma sensu, aby zadeklarować wskaźnik z typ MyClass
. Oto jeden możliwy sposób naprawienia tego przykładu:
MyClass m(string("blah blah blah"));
decltype(m) *pm; // uses type inference!
*pm = m;
Tutaj pm
jest już właściwego typu, więc wnioskowanie jest banalne. Co więcej, nie można przypadkowo pomieszać typów podczas wywoływania konstruktora kopiującego:
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
Tutaj pm
będzie wskaźnik do kopii m
. Tutaj MyClass
jest konstruowana na podstawie kopii - m
która jest typu MyClass<string>
(a nie typu nieistniejącego MyClass
). Tak więc, w miejscu, gdzie pm
„s typ jest wywnioskować, że jest wystarczająca ilość informacji, aby wiedzieć, że szablon-typ m
, a zatem szablon-typ pm
jest string
.
Co więcej, następujące informacje zawsze powodują błąd kompilacji :
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
Dzieje się tak, ponieważ deklaracja konstruktora kopiującego nie jest szablonem:
MyClass(const MyClass&);
W tym przypadku typ szablonu argumentu kopiuj-konstruktora jest zgodny z typem szablonu całej klasy; tj. kiedy MyClass<string>
jest tworzony, MyClass<string>::MyClass(const MyClass<string>&);
jest tworzony z nim, a kiedy MyClass<int>
jest tworzony, MyClass<int>::MyClass(const MyClass<int>&);
jest tworzony. O ile nie zostanie to jawnie określone lub nie zostanie zadeklarowany konstruktor oparty na szablonie, nie ma powodu, dla którego kompilator MyClass<int>::MyClass(const MyClass<string>&);
miałby tworzyć instancję , co oczywiście byłoby niewłaściwe.
Odpowiedź Cătălin Pitiș
Pitis podaje przykład wyciągania Variable<int>
i Variable<double>
, po czym stwierdza:
Mam tę samą nazwę typu (zmienna) w kodzie dla dwóch różnych typów (zmienna i zmienna). Z mojego subiektywnego punktu widzenia ma to duży wpływ na czytelność kodu.
Jak zauważono w poprzednim przykładzie, Variable
sama w sobie nie jest nazwą typu, mimo że nowa funkcja sprawia, że wygląda jak nazwa.
Pitiș pyta następnie, co by się stało, gdyby nie podano konstruktora, który pozwoliłby na odpowiednie wnioskowanie. Odpowiedź brzmi, że żadne wnioskowanie nie jest dozwolone, ponieważ jest ono wyzwalane przez wywołanie konstruktora . Bez wywołania konstruktora nie ma wnioskowania .
Jest to podobne do pytania o wersję foo
wydedukowaną tutaj:
template <typename T> foo();
foo();
Odpowiedź brzmi, że ten kod jest nielegalny z podanego powodu.
Odpowiedź MSaltera
O ile mi wiadomo, jest to jedyna odpowiedź, która może wzbudzić uzasadnione obawy dotyczące proponowanej funkcji.
Oto przykład:
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
Kluczowe pytanie brzmi: czy kompilator wybiera tutaj konstruktor wywodzący się z typu , czy konstruktor kopiujący ?
Wypróbowując kod, widzimy, że wybrany został konstruktor kopiujący. Aby rozwinąć przykład :
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
// Variable var4(Variable(num)); // compiler error
Nie jestem pewien, jak to określa propozycja i nowa wersja normy; wydaje się, że określają go „przewodniki po dedukcji”, które są nowym kawałkiem standardu, którego jeszcze nie rozumiem.
Nie jestem też pewien, dlaczego var4
odliczenie jest nielegalne; błąd kompilatora z g ++ wydaje się wskazywać, że instrukcja jest analizowana jako deklaracja funkcji.