Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
При определении шаблона класса необходимо организовать исходный код таким образом, чтобы определения элементов были видны компилятору, когда они ему нужны. Вы можете выбрать модель включения или модель явного создания экземпляра. В модели включения вы добавляете определения элементов в каждый файл, который использует шаблон. Это самый простой подход. Он обеспечивает максимальную гибкость с точки зрения того, какие конкретные типы могут использоваться в шаблоне. Его недостаток в том, что он может увеличивать время компиляции. Время может быть значительным, если проект или включенные файлы являются большими. В рамках подхода явного создания экземпляров сам шаблон создает экземпляры конкретных классов или элементов класса для определенных типов. Этот подход может уменьшить время компиляции, но он ограничивает использование только теми классами, которые разработчик шаблона включил заранее. Как правило, модель включения рекомендуется использовать, если время компиляции не является проблемой.
Общие сведения
Шаблоны не похожи на обычные классы в том смысле, что компилятор не создает код объекта для шаблона или любого из его членов. Нет ничего, пока шаблон не будет создан с конкретными типами. Когда компилятор обнаруживает создание экземпляра шаблона, такого как MyClass<int> mc;, и класс с такой сигнатурой еще не существует, он создает такой класс. Он также пытается создать код для любых используемых функций-элементов. Если эти определения находятся в файле, который не #included, прямо или косвенно, в скомпилированном файле .cpp компилятор их не может увидеть. С точки зрения компилятора это не обязательно ошибка. Функции могут быть определены в другом модуле перевода, где компоновщик найдет их. Если компоновщик не находит этот код, он вызывает неразрешенную внешнюю ошибку.
Модель включения
Самый простой и наиболее распространенный способ сделать определения шаблонов видимыми во всей записи преобразования — это поместить определения в сам файл заголовка. Любой .cpp файл, использующий шаблон, просто должен быть #include заголовок. Этот подход используется в стандартной библиотеке.
#ifndef MYARRAY
#define MYARRAY
#include <iostream>
template<typename T, size_t N>
class MyArray
{
T arr[N];
public:
// Full definitions:
MyArray(){}
void Print()
{
for (const auto v : arr)
{
std::cout << v << " , ";
}
}
T& operator[](int i)
{
return arr[i];
}
};
#endif
При таком подходе у компилятора есть доступ к полному определению шаблона и он может создавать экземпляры шаблонов любого типа по запросу. Это просто и относительно легко поддерживать. Тем не менее модель включения затратнее с точки зрения времени компиляции. Эти затраты могут возрасти в крупных программах, особенно если сам заголовок шаблона содержит (#include) другие заголовки. Каждый .cpp файл, #includes заголовок, получит собственную копию шаблонов функций и все определения. Компоновщик, как правило, сможет отсортировать вещи, чтобы не получить несколько определений для функции, но это займет некоторое время. В случае небольших программ дополнительное время компиляции будет существенно меньше.
Модель явного создания экземпляра
Если модель включения не подходит для проекта, и вы знаете окончательно набор типов, которые будут использоваться для создания экземпляра шаблона, то вы можете разделить код шаблона на .h файл .cpp и .cpp явно создать экземпляр шаблонов. Этот подход создает код объекта, который компилятор увидит при обнаружении экземпляров пользователей.
Вы создаете явное создание экземпляра с помощью ключевого слова template , за которым следует сигнатура сущности, которую требуется создать. Эта сущность может быть типом или членом. Если вы явно создаете экземпляр типа, будут созданы все элементы.
Файл MyArray.h заголовка объявляет класс MyArrayшаблона:
//MyArray.h
#ifndef MYARRAY
#define MYARRAY
template<typename T, size_t N>
class MyArray
{
T arr[N];
public:
MyArray();
void Print();
T& operator[](int i);
};
#endif
Исходный файл MyArray.cpp явно создает экземпляры template MyArray<double, 5> и template MyArray<string, 5>:
//MyArray.cpp
#include <iostream>
#include "MyArray.h"
using namespace std;
template<typename T, size_t N>
MyArray<T,N>::MyArray(){}
template<typename T, size_t N>
void MyArray<T,N>::Print()
{
for (const auto v : arr)
{
cout << v << "'";
}
cout << endl;
}
template MyArray<double, 5>;
template MyArray<string, 5>;
В предыдущем примере явные экземпляры находятся в нижней .cpp части файла. Может MyArray использоваться только для double типов или String типов.
Примечание.
В C++11 ключевое export слово было устарело в контексте определений шаблонов. На практике это мало что дает, потому что большинство компиляторов никогда его не поддерживали.