Пространства имён
Варианты
Действия

Шаблон класса

Материал из cppreference.com
< cpp‎ | language

Шаблон класса определяет семейство классов.

Содержание

[править] Синтаксис

template < список-параметров > объявление-класса (1)
export template < параметр-list > объявление-класса (2) (до C++11)

[править] Объяснение

объявление-класса a объявление класса. Объявленное имя класса становится именем шаблона.
список-параметров непустой список параметров шаблона, разделённых запятыми, каждый из которых является нетиповым параметром, типовым параметром, шаблоном-параметром шаблона, или пакетом параметров из них.
Модификатор explicit был необязательным и объявлял шаблон экспортируемым (при использовании с шаблоном класса он объявлял все его члены также экспортируемыми). В исходных файлы, которые инстанцировали экспортируемые шаблоны, не нужно было включать их определения - было достаточно объявлений. Реализации export были редки и не согласованы в деталях друг с другом. (до C++11)

[править] Инстанцирование шаблона класса

Шаблон класса сам по себе не является ни типом, ни объектом, ни любой другой сущностью. Из исходного файла, содержащего только определения шаблонов, не генерируется никакого кода. Чтобы компилятор сгенерировал код, данный шаблон должен быть инстанцирован, для чего из шаблона должен быть создан конкретный класс с набором аргументов (или функция для шаблона функции).

[править] Явное инстанцирование

template class|struct имя-шаблона < список-аргументов > ; (1)
export template class|struct имя-шаблона < список-аргументов > ; (2) (начиная с C++11)
1) Явное определение инстанцирования
2) Явное объявление инстанцирования

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

Явное объявление инстанцирования (внешний шаблон) пропускает шаг неявного инстанцирования: код, который иначе бы привёл к неявному инстанцированию, вместо этого использует явное определение инстанцирования, где-либо указанное. Если такого инстанцирования не было, то возникнут ошибки связывания (link errors). Можно уменьшить время компиляции, явно объявив инстанцирование шаблона во всех исходных файлах, использующих его, кроме того, где этот шаблон явно определяется. (начиная с C++11)

Классы, функции, переменные, и специализации шаблона-члена могут быть явно инстанцированы из их шаблонов. Функции-члены, классы-члены, и статические данные-члены шаблонов классов могут быть явно инстанцированы из их определений как членов.

Явное инстанцирование шаблона может быть указано только в его объемлющем пространстве имён, если только не используется квалифицированный идентификатор:

namespace N 
{
  template<class T> 
  class Y // определение шаблона
  { 
    void mf() { } 
  }; 
}
// template class Y<int>; 	  // ошибка: шаблон класса Y не видим в глобальном пространстве имён
using N::Y;
// template class Y<int>; 	  // ошибка: явное инстанцирование вне пространства имён шаблона
template class N::Y<char*>;       // OK: явное инстанцирование
template void N::Y<double>::mf(); // OK: явное инстанцирование

Явное инстанцирование не имеет эффекта, если явная специализация для того же набора аргументов шаблона уже была указана ранее.

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

Если шаблон функции, шаблон переменной, шаблон функции-члена, или функция-член или статический член-данное шаблона класса явно инстанцируются при помощи явного объявления инстанцирования, определение шаблона должно быть указано в той же единице трансляции.

Когда явное инстанцирование именует специализацию шаблона класса, оно выступает как явное инстанцирование (объявления или определения) всех его неунаследованных нешаблонных членов, которые не были ранее явно специализированы в этой единице трансляции. Если этo явное инстанцирование является определением, оно также является явным объявлением инстанцирования только для тех членов, которые к этому моменту уже определены.

Явные объявления инстанцирования игнорируют спецификаторы доступа к члену класса - типы параметров и возвращаемые типы могут быть приватными.

[править] Неявное инстанцирование

Когда код ссылается на шаблон в контексте, который требует полностью определённого типа, или когда полнота типа влияет на код, и этoт конкретный тип не был явно инстанцирован, то происходит неявное инстанцирование. Например, когда создаётся объект этoго типа, но не указатель на этoт тип.

Это применимо и к членам шаблона класса - если данный член не использован в программе, то он не инстанцируется и не требует определения.

template<class T> 
struct Z // определение шаблона
{
    void f() {}
    void g(); // нет определения
}; 
template struct Z<double>; // явное инстанцирование Z<double>
Z<int> a; 		   // неявное инстанцирование Z<int>
Z<char>* p; 		   // здесь ничего не инстанцируется
p->f(); 		   // здесь происходит неявное инстанцирование Z<char> и Z<char>::f().
 
// Z<char>::g() нигде не вызывается, поэтому не инстанцируется, а значит не требуется определения

Если шаблон класса был объявлен, но к моменту инстанцирования не определен, то данное инстанцирование приводит к ситуации неполноты типа:

template<class T> 
class X; 	// объявление, не определение
 
X<char> ch;     // ошибка: X<char> - неполный тип
Локальные классы и любые шаблоны, использованые в их членах, инстанцируюся как часть инстанцирования данной сущности, в рамках которой объявлен данный локальный класс или перечисление. (начиная с C++17)

[править] Смотри также