Standard C ++ 17 wprowadza „przewodniki po odliczaniu szablonów”. Rozumiem, że mają one coś wspólnego z nową dedukcją argumentów szablonu dla konstruktorów wprowadzoną w tej wersji standardu, ale nie widziałem jeszcze prostego wyjaśnienia w stylu FAQ, czym one są i do czego służą.
Jakie są przewodniki po odliczaniu szablonów w C ++ 17?
Dlaczego (i kiedy) ich potrzebujemy?
Jak je zgłosić?
Odpowiedzi:
Przewodniki dedukcji szablonów to wzorce skojarzone z klasą szablonu, które informują kompilator, jak przetłumaczyć zestaw argumentów konstruktora (i ich typów) na parametry szablonu dla klasy.
Najprostszym przykładem jest of
std::vector
i jego konstruktor, który przyjmuje parę iteratorów.template<typename Iterator> void func(Iterator first, Iterator last) { vector v(first, last); }
Kompilator musi dowiedzieć się, co
vector<T>
jestT
typ będzie. Wiemy, jaka jest odpowiedź;T
powinno byćtypename std::iterator_traits<Iterator>::value_type
. Ale jak powiemy kompilatorowi bez konieczności wpisywaniavector<typename std::iterator_traits<Iterator>::value_type>
?Korzystasz z przewodnika po odliczeniach:
template<typename Iterator> vector(Iterator b, Iterator e) -> vector<typename std::iterator_traits<Iterator>::value_type>;
To mówi kompilatorowi, że po wywołaniu
vector
konstruktora pasującego do tego wzorca, wywnioskuje onvector
specjalizację przy użyciu kodu po prawej stronie->
.Potrzebujesz wskazówek, gdy dedukcja typu z argumentów nie jest oparta na typie jednego z tych argumentów. Inicjowanie a
vector
zinitializer_list
jawnie używavector
'sT
, więc nie potrzebuje przewodnika.Lewa strona niekoniecznie określa faktyczny konstruktor. Sposób, w jaki to działa, polega na tym, że jeśli używasz dedukcji konstruktora szablonu na typie, pasuje ona do argumentów, które przekazujesz we wszystkich przewodnikach dedukcji (rzeczywiste konstruktory szablonu podstawowego zapewniają niejawne przewodniki). Jeśli istnieje dopasowanie, używa go do określenia, które argumenty szablonu mają dostarczyć do typu.
Ale po wykonaniu tej dedukcji, gdy kompilator ustali parametry szablonu dla typu, inicjalizacja obiektu tego typu przebiega tak, jakby nic takiego się nie stało. Oznacza to, że wybrany przewodnik dedukcji nie musi pasować do wybranego konstruktora .
Oznacza to również, że możesz używać przewodników z agregatami i inicjalizacją agregatów:
template<typename T> struct Thingy { T t; }; Thingy(const char *) -> Thingy<std::string>; Thingy thing{"A String"}; //thing.t is a `std::string`.
Tak więc przewodniki dedukcji służą tylko do określenia inicjowanego typu. Rzeczywisty proces inicjalizacji przebiega dokładnie tak samo, jak wcześniej, po dokonaniu tego ustalenia.
źródło
vector v{first, last};
nie zrobi dobrze :(std::string{32,'*'}[0] == ' '
(dla ASCII). Ale to wszystko jest prawdą od czasu C ++ 11.