Определения шаблонов вне класса
Это O.K. определить виртуальную функцию шаблона класса вне ее тела? Виртуальная функция не может быть встроена, но чтобы избежать множественных определений в единицах компиляции, они должны быть отмечены inline
(при условии, что заголовки шаблонов будут включены в несколько исходных файлов). С другой стороны, компилятор может игнорировать inline
, поэтому это кажется правильным. В качестве примера приведен правильный код:
template <typename T>
class C
{
public:
virtual void f(T val);
};
template <typename T>
inline
void C<T>::f(T val)
{
//definition
}
?
BTW gcc (3.4.2) позволяет пропустить inline
до определения функции f(T val)
, но не до аналогичной функции обычного класса. Это только gcc-поведение?
Ответы
Ответ 1
Да, это нормально даже без inline
. Он работает одинаково для обычных функций-членов и статических переменных:
// everything in the header:
template <class T>
class A
{
static int i;
};
template <class T>
int A<T>::i=0;
Стандартная цитата: (3.2/5)
Может быть несколько определений типа класса (раздел 9), тип перечисления (7.2), встроенная функция с внешняя связь (7.1.2), шаблон класса (раздел 14), шаблон нестатической функции (14.5.6), элемент статических данных шаблона класса (14.5.1.3), функции-члена шаблона класса (14.5.1.1) или специализации шаблона для которые некоторые параметры шаблона не указаны (14.7, 14.5.5) в программе, при условии, что каждое определение появляется в отдельной единицы перевода и при условии, что определения удовлетворяют следующим требованиям...
Требования в основном говорят, что два определения должны быть идентичными.
Это не работает в случае обычных классов. Должно быть не более одного определения во всей программе.
Ответ 2
Вы можете определить методы шаблона вне определения class
в том же заголовке без использования inline
и без получения нескольких ошибок определения.
Это потому, что функция шаблона не генерирует само определение, если оно не полностью специализировано. Чтобы доказать свою точку зрения, выполните следующие действия:
void C<int>::f(int)
{
}
приведет к ошибке компоновщика, так как функция имеет определение в этом случае. (при условии, что вы включили это в несколько единиц перевода. Если вы пометили его inline:
inline void C<int>::f(int)
{
}
ошибка больше не возникает.
Ответ 3
Вы можете определить функции там, если любой код, который должен создать экземпляр рассматриваемой функции, имеет видимость этого кода во время компиляции (не время ссылки).
Весьма распространено разделение шаблона на 2 файла, один из которых является традиционным заголовком, а второй - реализацией, как и в случае не-шаблонных функций и их реализации. Единственное различие заключается в том, что вам нужно # включить файл реализации шаблона, а также заголовок, когда вы хотите его использовать.