Что такое руководства по выбору шаблонов и когда их следует использовать?

87

Стандарт C ++ 17 представляет «руководства по выводам шаблонов». Я так понимаю, они как-то связаны с новым выводом аргументов шаблона для конструкторов, представленным в этой версии стандарта, но я еще не видел простого объяснения в стиле FAQ, что они собой представляют и для чего они нужны.

  • Что такое руководства по выводам шаблонов в C ++ 17?

  • Зачем (и когда) они нам нужны?

  • Как мне их объявить?

Тристан Бриндл
источник
В частности, мне было бы интересно узнать, действительно ли C ++ 17 STL предоставляет какие-либо руководства по выводам (например, для std :: pair или std :: tuple). Каков полный список "выводимых" стандартных типов шаблонов в C ++ 17?
Quuxplusone
Мне было бы интересно узнать, поддерживает ли это какой-либо компилятор. Я пробовал gcc, clang и vc ++. rextester.com/DHPHC32332 Nevermind, я обнаружил, что он работает только с gc ++ 8.1 C ++ 17 и 2a g ++ -std = c ++ 17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Жан-Симон Brochu

Ответы:

98

Руководства по выводу шаблонов - это шаблоны, связанные с классом шаблона, которые сообщают компилятору, как преобразовать набор аргументов конструктора (и их типы) в параметры шаблона для класса.

Самый простой пример - это конструктор of std::vectorи его конструктор, который принимает пару итераторов.

template<typename Iterator>
void func(Iterator first, Iterator last)
{
  vector v(first, last);
}

Компилятор должен понять, что vector<T>«s Tтипа будет. Мы знаем ответ; 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's T, поэтому руководство не требуется.

Левая сторона не обязательно указывает фактический конструктор. Это работает следующим образом: если вы используете вывод конструктора шаблона для типа, он соответствует аргументам, которые вы передаете всем руководствам по выводам (фактические конструкторы основного шаблона предоставляют неявные руководства). Если есть совпадение, он использует это, чтобы определить, какие аргументы шаблона предоставить типу.

Но как только этот вывод сделан, когда компилятор определит параметры шаблона для типа, инициализация объекта этого типа продолжается, как если бы ничего из этого не произошло. То есть, выбранный метод вывода не обязательно должен соответствовать выбранному конструктору .

Это также означает, что вы можете использовать руководства с агрегатами и агрегатной инициализацией:

template<typename T>
struct Thingy
{
  T t;
};

Thingy(const char *) -> Thingy<std::string>;

Thingy thing{"A String"}; //thing.t is a `std::string`.

Таким образом, руководства по дедукции используются только для определения инициализируемого типа. Фактический процесс инициализации работает точно так же, как и раньше, после того, как это определение было сделано.

Николь Болас
источник
7
Хм, мне только что пришло в голову, что даже с гидом vector v{first, last};ничего не получится :(
TC
3
@TC… если только не нужно создавать вектор итераторов. И std::string{32,'*'}[0] == ' '(для ASCII). Но все это было правдой со времен C ++ 11.
Арне Фогель
2
что происходит с параметром вектора распределителя? что бы произошло, если бы у параметра вектора распределителя не было аргумента по умолчанию? (вы не можете вывести его из InputIterator)
gnzlbg
@NicolBolas: Не могли бы вы объяснить подробности того, как неявные и явные руководства по дедукции могут работать в контексте частично или полностью специализированных классов (конструкторы которых явно не нуждаются в том, чтобы типы параметров соответствовали типам параметров основного шаблона)? Информацию об этом сложно найти с помощью быстрого поиска.
user541686
1
@NicolBolas: Понятно. Мне не совсем понятно, что вопрос вообще касается явных руководств по дедукции ... Я думаю, будет полезно, если вы просто включите то, что буквально написали в этом комментарии.
user541686