Конкретизированный экземпляр шаблона будет иметь соответственно имя Queueint или Queuestring. Части int и string, следующие за именем Queue, называются фактическими аргументами шаблона. Они должны быть заключены в угловые скобки и отделяться друг от друга запятыми. В имени конкретизируемого шаблона аргументы всегда должны задаваться явно. В отличие от аргументов шаблона функции, аргументы шаблона класса никогда не выводятся из контекста:
Queue qs; // ошибка: как конкретизируется шаблон?
Конкретизированный шаблон класса Queue можно использовать в программе всюду, где допустимо употребление типа обычного класса:
// типы возвращаемого значения и обоих параметров конкретизированы из
// шаблона класса Queue
foo( Queue complexdouble &, Queue complex&double&& & );
// указатель на функцию-член класса, конкретизированного из шаблона Queue
bool (Queuedouble::*pmf)() = 0;
// явное приведение 0 к указателю на экземпляр Queue
Queuechar* *pqc = static_cast Queuechar** ( 0 );
Объекты типа класса, конкретизированного по шаблону Queue, объявляются и используются так же, как объекты обычных классов:
extern Queuedoubleeqd;
Queueint *pqi = new Queueint;
Queueint aqi[1024];
int main() {
ретизированный по нему класс:
// объявление шаблона функции
template class Type
void bar( QueueType &, // ссылается на обобщенный шаблон
Queuedouble & // ссылается на конкретизированный шаблон
)
Однако вне такого определения употребляются только конкретизированные экземпляры. Например, в теле обычной функции всегда надо задавать фактические аргументы шаблона Queue:
void foo( Queueint &qi )
{
Queueint *pq =
// ...
}
Шаблон класса конкретизируется только тогда, когда имя полученного экземпляра употребляется в контексте, где требуется определение шаблона. Не всегда определение класса должно быть известно. Например, перед объявлением указателей и ссылок на класс его знать необязательно:
class Matrix;
Matrix *pm; // правильно: определение класса Matrix знать необязательно
void inverse( Matrix & ); // тоже правильно
Поэтому объявление указателей и ссылок на конкретизированный шаблон класса не приводит к его конкретизации. (Отметим, что в некоторых компиляторах, написанных до принятия стандарта C++, шаблон конкретизируется при первом упоминании имени конкретизированного класса в тексте программы.) Так, в функции foo() объявляются указатель и ссылка на Queue, но это не вызывает конкретизации шаблона Queue:
// Queueint не конкретизируется при таком использовании в foo()
void foo( Queueint &qi )
{
Queueint *pqi =
// ...
}
Определение класса необходимо знать, когда определяется объект этого типа. В следующем примере определение obj1 ошибочно: чтобы выделить для него память, компилятору необходимо знать размер класса Matrix:
class Matrix;
Matrix obj1; // ошибка: класс Matrix не определен
class Matrix { ... };
Matrix obj2; // правильно
Таким образом, конкретизация происходит тогда, когда определяется объект класса, конкретизированного по этому шаблону. В следующем примере определение объекта qi приводит к конкретизации шаблона Queue:
Queueint qi; // конкретизируется Queueint
Определение Queueint становится известно компилятору именно в этой точке, которая называется точкой конкретизации данного класса.
Если имеется указатель или ссылка на конкретизированный шаблон, то конкретизация также производится в момент обращения к объекту, на который они ссылаются. В определенной выше функции foo() класс Queue конкретизируется в следующих случаях: когда разыменовывается указатель pqi, когда ссылка qi используется для получения значения именуемого объекта и когда pqi или qi употребляются для доступа к членам или функциям-членам этого класса:
void foo( Queueint &qi )
{
Queueint *pqi =
// Queue конкретизируется в результате вызова функции-члена
pqi-add( 255 );
// ...
}