Шаблоны
Шаблон — это сущность C++, которая определяет один из следующих элементов:
- семейство классов (шаблон класса), которое может содержать вложенные классы
- семейство функций (шаблон функции), которое может содержать функции-члены
| (начиная с C++11) |
| (начиная с C++14) |
| (начиная с C++20) |
Шаблоны параметризуются одним или несколькими параметрами шаблона трех видов: параметрами шаблона типа, параметрами шаблона нетипового значения и параметрами шаблона шаблона.
Когда аргументы шаблона заданы или, только для шаблонов функций и классов(начиная с C++17), выведены, они подставляются вместо параметров шаблона, чтобы получить специализацию шаблона, то есть конкретный тип или конкретное lvalue функции.
Специализации также можно задавать явно: полные специализации допускаются для шаблонов классов, переменных(начиная с C++14) и функций, а частичные специализации допускаются только для шаблонов классов и шаблонов переменных(начиная с C++14).
Когда на специализацию шаблона класса ссылаются в контексте, требующем полного типа объекта, или когда на специализацию шаблона функции ссылаются в контексте, требующем наличия определения функции, шаблон инстанцируется (код для него фактически компилируется), если только шаблон уже не был явно специализирован или явно инстанцирован. Инстанцирование шаблона класса не инстанцирует ни одну из его функций-членов, если они также не используются. Во время компоновки идентичные инстанцирования, созданные разными единицами трансляции, объединяются.
Определение шаблона класса должно быть видимо в точке неявного инстанцирования, поэтому библиотеки шаблонов обычно предоставляют все определения шаблонов в заголовочных файлах (например, большинство библиотек boost распространяются только в виде заголовочных файлов).
Синтаксис
template <parameter-list > requires-clause (необязательно) declaration | (1) | |
export template <parameter-list > declaration | (2) | (до C++11) |
template <parameter-list > concept concept-name = constraint-expression ; | (3) | (начиная с C++20) |
| parameter-list | - | непустой список параметров шаблона, разделенных запятыми; каждый из них является либо нетиповым параметром, либо параметром типа, либо параметром шаблона, либо пакетом параметров любого из этих видов(начиная с C++11). |
| requires-clause | - | (начиная с C++20) предложение requires, задающее ограничения на аргументы шаблона. |
| declaration | - | объявление класса (включая struct и union), класса-члена или типа перечисления-члена, функции или функции-члена, статического члена данных в пространстве имен, переменной или статического члена данных в области видимости класса(начиная с C++14) или шаблона псевдонима(начиная с C++11). Оно также может определять специализацию шаблона. |
|
concept-name constraint-expression | - | см. ограничения и концепты |
| export был необязательным модификатором, который объявлял шаблон как экспортируемый (при использовании с шаблоном класса он также объявлял экспортируемыми все его члены). Файлам, инстанцирующим экспортируемые шаблоны, не требовалось включать их определения: было достаточно объявления. Реализации export встречались редко и различались в деталях. | (до C++11) |
Идентификаторы шаблонов
Идентификатор шаблона имеет один из следующих синтаксисов:
template-name <template-argument-list (необязательно)> | (1) | |
operatorop <template-argument-list (необязательно)> | (2) | |
operator "" identifier <template-argument-list (необязательно)> | (3) |
(начиная с C++11) (устарело) |
operator user-defined-string-literal <template-argument-list (необязательно)> | (4) | (начиная с C++11) |
| template-name | - | идентификатор, обозначающий шаблон |
| op | - | перегружаемый оператор |
| identifier | - | идентификатор |
| user-defined-string-literal | - |
"", за которым следует идентификатор |
Простой идентификатор шаблона, обозначающий специализацию шаблона класса, обозначает класс.
Идентификатор шаблона, обозначающий специализацию шаблона псевдонима, обозначает тип.
Идентификатор шаблона, обозначающий специализацию шаблона функции, обозначает функцию.
Идентификатор шаблона является допустимым , если выполнены все следующие условия:
- Число аргументов не превышает число параметров либо один из параметров является пакетом параметров шаблона(начиная с C++11).
- Для каждого невыводимого параметра, не являющегося пакетом(начиная с C++11), у которого нет аргумента шаблона по умолчанию, задан аргумент.
- Каждый аргумент шаблона соответствует параметру шаблона.
- Подстановка каждого аргумента шаблона в следующие параметры шаблона (если таковые имеются) завершается успешно.
| (начиная с C++20) |
Недопустимый простой идентификатор шаблона является ошибкой времени компиляции, если только он не обозначает специализацию шаблона функции (в этом случае может применяться SFINAE).
template<class T, T::type n = 0>
class X;
struct S
{
using type = int;
};
using T1 = X<S, int, int>; // error: too many arguments
using T2 = X<>; // error: no default argument for first template parameter
using T3 = X<1>; // error: value 1 does not match type-parameter
using T4 = X<int>; // error: substitution failure for second template parameter
using T5 = X<S>; // OK
| Если template-name простого идентификатора шаблона обозначает ограниченный нешаблонный шаблон функции или ограниченный параметр шаблона шаблона, но не шаблон-член, являющийся членом неизвестной специализации, и все аргументы шаблона в простом идентификаторе шаблона являются независимыми, ограничения ограниченного шаблона должны быть удовлетворены: template<typename T>
concept C1 = sizeof(T) != sizeof(int);
template<C1 T>
struct S1 {};
template<C1 T>
using Ptr = T*;
S1<int>* p; // error: constraints not satisfied
Ptr<int> p; // error: constraints not satisfied
template<typename T>
struct S2 { Ptr<int> x; }; // error, no diagnostic required
template<typename T>
struct S3 { Ptr<T> x; }; // OK, satisfaction is not required
S3<int> x; // error: constraints not satisfied
template<template<C1 T> class X>
struct S4
{
X<int> x; // error, no diagnostic required
};
template<typename T>
concept C2 = sizeof(T) == 1;
template<C2 T> struct S {};
template struct S<char[2]>; // error: constraints not satisfied
template<> struct S<char[2]> {}; // error: constraints not satisfied
| (начиная с C++20) |
Два идентификатора шаблонов являются одинаковыми , если выполнены все следующие условия:
- Их template-name ы или операторы ссылаются на один и тот же шаблон.
- Соответствующие аргументы шаблона типа имеют один и тот же тип.
- Значения параметров шаблона, определяемые соответствующими нетиповыми аргументами шаблона, являются эквивалентными аргументам шаблона.
- Соответствующие аргументы шаблона шаблона ссылаются на один и тот же шаблон.
Два одинаковых идентификатора шаблонов ссылаются на одну и ту же переменную,(начиная с C++14) класс или функцию.
Сущность, являющаяся шаблоном
Сущность, являющаяся шаблоном (или, в некоторых источниках, «temploid») — это любая сущность, определенная (или созданная для лямбда-выражения)(начиная с C++11) внутри определения шаблона. К сущностям, являющимся шаблонами, относятся:
- шаблон
| (начиная с C++26) |
- сущность, определенная или созданная внутри сущности, являющейся шаблоном (например, локальный класс, локальная переменная или переменная в блочной области видимости либо дружественная функция)
- член сущности, являющейся шаблоном (например, функция-член класса-шаблона, не являющаяся шаблоном)
- элемент перечисления, являющегося сущностью-шаблоном
| (начиная с C++11) |
Например, в
template<typename T>
struct A
{
void f() {}
};
функция A::f не является шаблоном функции, но все же считается сущностью, являющейся шаблоном.
Функция, являющаяся шаблоном, — это шаблон функции или функция, являющаяся шаблоном.
Класс, являющийся шаблоном, — это шаблон класса или класс, являющийся шаблоном.
| Переменная, являющаяся шаблоном, — это шаблон переменной или переменная, являющаяся шаблоном. | (начиная с C++14) |
Ключевые слова
Отчеты об ошибках стандарта
Следующие отчеты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение согласно опубликованному стандарту | Правильное поведение |
|---|---|---|---|
| CWG 2293 | C++98 | правила определения допустимости идентификатора шаблона отсутствовали | добавлены |
| CWG 2682 | C++98 C++14 | отсутствовали определения функции, являющейся шаблоном/ класса-шаблона (C++98)/переменной, являющейся шаблоном (C++14) | добавлены |
| P2308R1 | C++98 | два идентификатора шаблонов считались разными, если их соответствующие нетиповые аргументы шаблона не были эквивалентны аргументам шаблона | они считаются разными, если значения их соответствующих нетиповых параметров шаблона не эквивалентны аргументам шаблона |
См. также
| Документация по C о обобщенном выборе |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/templates