Программирование. Принципы и практика использования C++ Исправленное издание, стр. 259
При компиляции программы, использующей шаблоны, компилятор “заглядывает” внутрь шаблонов и его шаблонных аргументов. Он делает это для того, чтобы извлечь информацию, необходимую для генерирования оптимального кода. Для того чтобы эта информация стала доступной, современные компиляторы требуют, чтобы шаблон был полностью определен везде, где он используется. Это относится и к его функциям-членам и ко всем шаблонным функциям, вызываемым из них. В результате авторы шаблонов стараются разместить определения шаблонов в заголовочных файлах. На самом деле стандарт этого не требует, но пока не будут разработаны более эффективные реализации языка, мы рекомендуем вам поступать со своими шаблонами именно так: размещайте в заголовочном файле определения всех шаблонов, используемых в нескольких единицах трансляции.
vector19.3.3. Контейнеры и наследование
Это одна из разновидностей сочетания объектно-ориентированного и обобщенного программирования, которое люди постоянно, но безуспешно пытаются применять: использование контейнера объектов производного класса в качестве контейнера объектов базового класса. Рассмотрим пример.
vector<Shape> vs;vector<Circle> vc;vs = vc; // ошибка: требуется класс vector<Shape>void f(vector<Shape>&);f(vc); // ошибка: требуется класс vector<Shape>
CircleShapeCircle*Shape*Circle&Shape&ShapeShapeИтак, попытаемся снова использовать указатели.
vector<Shape*> vps;vector<Circle*> vpc;vps = vpc; // ошибка: требуется класс vector<Shape*>void f(vector<Shape*>&);f(vpc); // ошибка: требуется класс vector<Shape*>И вновь система типов сопротивляется. Почему? Рассмотрим, что может делать функция
f()void f(vector<Shape*>& v){ v.push_back(new Rectangle(Point(0,0),Point(100,100)));}
Rectangle*vector<Shape*>vector<Shape*>vector<Circle*>Rectangle*vpcDBC<D>C<B>C19.3.4. Целые типы как шаблонные параметры
Рассмотрим пример наиболее распространенного использования целочисленного значения в качестве шаблонного аргумента: контейнер, количество элементов которого известно уже на этапе компиляции.
template<class T, int N> struct array { T elem[N]; // хранит элементы в массиве - // члене класса, использует конструкторы по умолчанию, // деструктор и присваивание T& operator[] (int n); // доступ: возвращает ссылку const T& operator[] (int n) const; T* data() { return elem; } // преобразование в тип T* const T* data() const { return elem; } int size() const { return N; }}Мы можем использовать класс
array