Arrayint, 1024, bar a3; // ошибка: foo != PFV
Arrayint, x, bar a4; // правильно: преобразование не нужно
Arrayint, x, foo a5; // ошибка: foo != PFV
Объекты a0 и a4 класса Array определены правильно, так как аргументы шаблона точно соответствуют типам параметров. Объект a2 также определен правильно, потому что аргумент 1024 типа int приводится к типу unsigned int параметра-константы size с помощью преобразования целых типов. Объявления a1, a3 и a5 ошибочны, так как не существует преобразования между любыми двумя типами функций.
Приведение значения 0 целого типа к типу указателя недопустимо:
template int *ptr
class BufPtr { ... };
// ошибка: 0 имеет тип int
// неявное преобразование в нулевой указатель не применяется
BufPtr 0 nil;
Упражнение 16.3
Укажите, какие из данных конкретизированных шаблонов действительно приводят к конкретизации:
template class Type
class Stack { };
void f1( Stack char ); // (a)
class Exercise {
// ...
Stack double // (b)
Stack int si; // (c)
};
int main() {
Stack char *sc; // (d)
f1( *sc ); // (e)
int iObj = sizeof( Stack string ); // (f)
}
Упражнение 16.4
Какие из следующих конкретизаций шаблонов корректны? Почему?
template int *ptr class Ptr ( ... };
template class Type, int size class Fixed_Array { ... };
template int hi, int wid class Screen { ... };
(a) const int size = 1024;
Ptr &size&bp1
(b) int arr[10];
Ptr arr bp2;
(c) Ptr 0 bp3;
(d) const int hi = 40;
const int wi = 80;
Screen hi, wi+32 sObj;
(e) const int size_val = 1024;
Fixed_Array string, size_val fa1;
(f) unsigned int fasize = 255;
Fixed_Array int, fasize fa2;
(g) const double db = 3.1415;
Fixed_Array double, db fa3;
16.3. Функции-члены шаблонов классов
Как и для обычных классов, функция-член шаблона класса может быть определена либо внутри определения шаблона (и тогда называется встроенной), либо вне его. Мы уже встречались со встроенными функциями-членами при рассмотрении шаблона Queue. Например, конструктор Queue является встроенным, так как определен внутри определения шаблона класса:
template class Type
class Queue {
// ...
public:
// встроенный конструктор
Queue() : front( 0 ), back( 0 ) { }
// ...
};
При определении функции-члена шаблона вне определения самого шаблона следует применять специальный синтаксис для обозначения того, членом какого именно шаблона является функция. Определению функции-члена должно предшествовать ключевое слово template, за которым следуют параметры шаблона. Так, конструктор Queue можно определить следующим образом:
template class Type
class Queue {
public:
Queue();
private:
// ...
};
template class Type
inline Queue Type ::
Queue( ) { front = back = 0; }
За первым вхождением Queue (перед оператором ::) следует список параметров, показывающий, какому шаблону принадлежит данная функция-член. Второе вхождение Queue в определение конструктора (после оператора ::) содержит имя функции-члена, за которым может следовать список параметров шаблона, хотя это и необязательно. После имени функции идет ее определение;. в нем могут быть ссылки на параметр шаблона Type всюду, где в определении обычной функции использовалось бы имя типа.
Функция-член шаблона класса сама является шаблоном. Стандарт C++ требует, чтобы она конкретизировалась только при вызове либо при взятии ее адреса. (Некоторые более старые компиляторы конкретизируют такие функции одновременно с конкретизацией самого шаблона класса.) При конкретизации функции-члена используется тип того объекта, для которого функция вызвана:
Queue string qs;