Шаблон класса
Шаблон класса определяет семейство классов.
Синтаксис
template < parameter-list > class-declaration | (1) | |
template < parameter-list > requires constraint class-declaration | (2) | (начиная с C++20) |
export template < parameter-list > class-declaration | (3) | (удалено в C++11) |
Пояснение
| class-declaration | - | объявление класса. Объявленное имя класса становится именем шаблона. |
| parameter-list | - | непустой список разделённых запятыми параметров шаблона, каждый из которых является нетиповым параметром, параметром типа, параметром-шаблоном или пакетом параметров любого из этих видов. |
| constraint | - | выражение-ограничение, которое ограничивает набор параметров шаблона, допустимых для этого шаблона класса |
export был необязательным модификатором, который объявлял шаблон экспортируемым (при использовании с шаблоном класса он также объявлял экспортируемыми все его члены). Файлам, в которых инстанцировались экспортируемые шаблоны, не требовалось включать их определения: было достаточно объявления. Реализации export встречались редко и различались в деталях. | (до C++11) |
Инстанцирование шаблона класса
Шаблон класса сам по себе не является типом, объектом или какой-либо другой сущностью. Исходный файл, содержащий только определения шаблонов, не порождает код. Чтобы появился какой-либо код, шаблон необходимо инстанцировать: следует предоставить аргументы шаблона, чтобы компилятор мог создать реальный класс (или функцию для шаблона функции).
Явное инстанцирование
template class-key template-name < argument-list > ; | (1) | |
extern template class-key template-name < argument-list > ; | (2) | (начиная с C++11) |
| class-key | - |
class, struct или union |
Определение явного инстанцирования принудительно инстанцирует класс, структуру или объединение, на которые оно ссылается. Оно может появляться в программе в любом месте после определения шаблона и для заданного списка аргументов может встречаться во всей программе только один раз; диагностика не требуется.
| Объявление явного инстанцирования (extern template) пропускает этап неявного инстанцирования: код, который в противном случае вызвал бы неявное инстанцирование, использует предоставленное в другом месте определение явного инстанцирования (что приводит к ошибкам компоновки, если такого инстанцирования нет). Это можно использовать для сокращения времени компиляции: явно объявить инстанцирование шаблона во всех исходных файлах, кроме одного, где он используется, и явно определить его в оставшемся файле. | (начиная с C++11) |
Шаблоны классов, функций, переменных(начиная с C++14) и специализации шаблонов-членов можно явно инстанцировать на основе их шаблонов. Функции-члены, классы-члены и статические члены-данные шаблонов классов можно явно инстанцировать на основе их определений.
Явное инстанцирование может появляться только в окружающем пространстве имён шаблона, если только в нём не используется квалифицированный идентификатор:
namespace N
{
template<class T>
class Y // template definition
{
void mf() {}
};
}
// template class Y<int>; // error: class template Y not visible in the global namespace
using N::Y;
// template class Y<int>; // error: explicit instantiation outside
// of the namespace of the template
template class N::Y<char*>; // OK: explicit instantiation
template void N::Y<double>::mf(); // OK: explicit instantiation
Явное инстанцирование не действует, если ранее для того же набора аргументов шаблона появилась явная специализация.
При явном инстанцировании шаблона функции, шаблона переменной(начиная с C++14), функции-члена или статического члена-данных шаблона класса либо шаблона функции-члена достаточно, чтобы было видно только объявление. Полное определение должно находиться перед явным инстанцированием шаблона класса, класса-члена шаблона класса или шаблона класса-члена, если только ранее не появилась явная специализация с теми же аргументами шаблона.
Если шаблон функции, шаблон переменной(начиная с C++14), шаблон функции-члена, функция-член или статический член-данные шаблона класса явно инстанцируется с определением явного инстанцирования, определение шаблона должно присутствовать в той же единице трансляции.
Если явное инстанцирование указывает специализацию шаблона класса, оно служит явным инстанцированием того же вида (объявлением или определением) для каждого его нестатического, невиртуального члена, не являющегося шаблоном и не унаследованного, если этот член ранее не был явно специализирован в единице трансляции. Если это явное инстанцирование является определением, оно также представляет собой определение явного инстанцирования только для членов, которые к этому моменту уже определены.
Определения явного инстанцирования не учитывают спецификаторы доступа к членам: типы параметров и возвращаемые типы могут быть закрытыми.
Неявное инстанцирование
Неявное инстанцирование происходит, когда код обращается к шаблону в контексте, требующем полностью определённого типа, либо когда полнота типа влияет на код, и этот конкретный тип не был явно инстанцирован. Например, когда создаётся объект такого типа, но не когда создаётся указатель на этот тип.
Это относится и к членам шаблона класса: если член не используется в программе, он не инстанцируется, и его определение не требуется.
template<class T>
struct Z // template definition
{
void f() {}
void g(); // never defined
};
template struct Z<double>; // explicit instantiation of Z<double>
Z<int> a; // implicit instantiation of Z<int>
Z<char>* p; // nothing is instantiated here
p->f(); // implicit instantiation of Z<char> and Z<char>::f() occurs here.
// Z<char>::g() is never needed and never instantiated:
// it does not have to be defined
Если шаблон класса был объявлен, но не определён в точке инстанцирования, результатом инстанцирования будет неполный тип класса:
template<class T> class X; // declaration, not definition X<char> ch; // error: incomplete type X<char>
| Локальные классы и любые шаблоны, используемые в их членах, инстанцируются как часть инстанцирования сущности, внутри которой объявлен локальный класс или перечисление. | (начиная с C++17) |
Ключевые слова
export(до C++11)extern(начиная с C++11)
См. также
- Параметры и аргументы шаблона позволяют задавать параметры шаблонов
- Объявление шаблона функции объявляет шаблон функции
- Специализация шаблона задаёт определение существующего шаблона для конкретного типа
- Пакеты параметров позволяют использовать в шаблонах списки типов (начиная с C++11)
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/class_template