Стандарт C ++ 17 представляет «руководства по выводам шаблонов». Я так понимаю, они как-то связаны с новым выводом аргументов шаблона для конструкторов, представленным в этой версии стандарта, но я еще не видел простого объяснения в стиле FAQ, что они собой представляют и для чего они нужны.
Что такое руководства по выводам шаблонов в C ++ 17?
Зачем (и когда) они нам нужны?
Как мне их объявить?
Ответы:
Руководства по выводу шаблонов - это шаблоны, связанные с классом шаблона, которые сообщают компилятору, как преобразовать набор аргументов конструктора (и их типы) в параметры шаблона для класса.
Самый простой пример - это конструктор of
std::vector
и его конструктор, который принимает пару итераторов.template<typename Iterator> void func(Iterator first, Iterator last) { vector v(first, last); }
Компилятор должен понять, что
vector<T>
«sT
типа будет. Мы знаем ответ;T
должно бытьtypename std::iterator_traits<Iterator>::value_type
. Но как сообщить компилятору, не набирая текстvector<typename std::iterator_traits<Iterator>::value_type>
?Вы используете руководство по дедукции:
template<typename Iterator> vector(Iterator b, Iterator e) -> vector<typename std::iterator_traits<Iterator>::value_type>;
Это сообщает компилятору, что, когда вы вызываете
vector
конструктор, соответствующий этому шаблону, он будет определятьvector
специализацию, используя код справа от->
.Руководства нужны, когда вывод типа из аргументов не основан на типе одного из этих аргументов. Инициализация a
vector
изinitializer_list
явно используетvector
'sT
, поэтому руководство не требуется.Левая сторона не обязательно указывает фактический конструктор. Это работает следующим образом: если вы используете вывод конструктора шаблона для типа, он соответствует аргументам, которые вы передаете всем руководствам по выводам (фактические конструкторы основного шаблона предоставляют неявные руководства). Если есть совпадение, он использует это, чтобы определить, какие аргументы шаблона предоставить типу.
Но как только этот вывод сделан, когда компилятор определит параметры шаблона для типа, инициализация объекта этого типа продолжается, как если бы ничего из этого не произошло. То есть, выбранный метод вывода не обязательно должен соответствовать выбранному конструктору .
Это также означает, что вы можете использовать руководства с агрегатами и агрегатной инициализацией:
template<typename T> struct Thingy { T t; }; Thingy(const char *) -> Thingy<std::string>; Thingy thing{"A String"}; //thing.t is a `std::string`.
Таким образом, руководства по дедукции используются только для определения инициализируемого типа. Фактический процесс инициализации работает точно так же, как и раньше, после того, как это определение было сделано.
источник
vector v{first, last};
ничего не получится :(std::string{32,'*'}[0] == ' '
(для ASCII). Но все это было правдой со времен C ++ 11.