Выбрать главу

Можно определить класс, который задает шаблонный класс, например:

template‹class T› class stream {/*… */};

class stream‹char› {/*… */};

Здесь описание класса будет использоваться в качестве определения потока символов (stream‹char›). Другие потоки будут управляться с помощью шаблонных функций, создаваемых по шаблону типа для функций.

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

R.14.6 Функции-члены шаблонов типа

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

template‹class T› class vector {

 T* v;

 int sz;

public:

 vector(int);

 T& operator[](int);

 T& elem(int i) { return v[i]; }

 //…

};

Функцию, выполняющую индексацию, можно определить следующим образом:

template‹class T› T& vector‹T›::operator[](int i)

{

 if (i‹0 || sz›=i) error("vector: range error");

 return v[i];

}

Шаблонный параметр для vector‹T›::operator[]() будет задаваться тем типом vector, к которому применяется операция индексации.

vector‹int› v1(20);

vector‹complex› v2(30);

v1[3] = 7; // vector‹int›::operator[]()

v2[3] = complex(7,8); // vector‹complex›::operator[]()

R.14.7 Друзья

Функция-друг для шаблона типа не является неявной шаблонной функцией, например:

template‹class T› class task {

 //…

 friend void next_time();

 friend task‹T›* preempt(task‹T›*);

 friend task* prmt(task*); // ошибка

 //…

};

Здесь функция next_time() становится другом всех классов task, а каждый класс task имеет в качестве друга функцию preempt() c соответствующими типами параметров. Функцию preempt() можно определить как шаблон типа.

template‹class T›

task‹T›* preempt(task‹T›* t) {/*… */}

Описание функции prmt() является ошибочным, поскольку типа task не существует, а есть только специальные шаблонные типы task‹int›, task‹record›, и т.д.

R.14.8 Статические члены и переменные

Для каждого шаблонного класса или функции, создаваемых по шаблону типа, образуется своя копия статических переменных или членов. Рассмотрим пример:

template‹class T› class X {

 static T s;

 //…

};

X‹int› aa;

X‹char*› bb;

Здесь в классе X‹int› есть статический член типа int, а в классе X‹char› есть статический член типа char*.

Аналогично, в приведенном ниже примере, функция f(int*) имеет статический член s типа int, а функция f(char**) имеет статический член типа char**:

template‹class T› f(T* p)

{

 static T s;

 //…

}

void g(int a, char* b)

{

 f(&a);

 f(&b);

}

R.15 Обработка особых ситуаций

R.15.1 Обработка особых ситуаций

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

проверяемый-блок:

 try составной-оператор список-обработчиков

список-обработчиков:

 обработчик список-обработчиков opt

обработчик:

 catch ( описание-особой-ситуации ) составной-оператор

описание-особой-ситуации:

 список-спецификаций-типа описатель

 список-спецификаций-типа абстрактный-описатель

 список-спецификаций-типа

 …

выражение-запуска:

 throw выражение opt

Конструкция проверяемый-блок является оператором (§R.6), а выражение-запуска - унарным выражением типа void (§R.5). Иногда выражение-запуска называют "точкой запуска", а про функцию, в которой встретилось выражение-запуска, говорят, что она "запускает особую ситуацию. Часть программы, которой передается управление из точки запуска называется обработчиком.

R.15.2 Запуск особой ситуации

При запуске особой ситуации управление передается обработчику. Запуск сопровождается передачей объект, тип которого определяет, какой обработчик должен перехватить особую ситуацию. Так, выражение

throw "Help!";

может быть перехвачено некоторым обработчиком с типом char*:

try {

 //…

}

catch(const char* p) {

 // здесь обрабатывается особая ситуация в символьных строках