Шаблоны C++ должны быть определены (с полным телом функции) в той же единице перевода (файл .CPP плюс все включенные заголовочные файлы), где они используются. В вашем заголовочном файле все, что вы сделали, это объявили (с учетом имени и подписи) функцию. В результате, когда вы включаете base.h
, все, что видит компилятор, это:
class Base {
template <typename T> void test(T a);
}
Это объявляет, но не определяет функцию. Чтобы определить его, вы должны включить тело функции:
class Base {
template <typename T> void test(T a)
{
// do something cool with a here
}
}
Причина, по которой это требуется, заключается в том, что компилятор C++ генерирует код для шаблонов по мере необходимости. Например, если вы позвоните:
Base obj;
obj.test< int >( 1 );
obj.test< char >( 'c' );
Компилятор сгенерирует два набора машинного кода на основе шаблона Base::test
, один для int
и один для char
. Ограничение здесь состоит в том, что определение шаблона Base::test
должно находиться в одной и той же единице трансляции (файл .CPP), иначе компилятор не будет знать, как построить машинный код для каждой версии функции Base::test
. Компилятор работает только с одной единицей перевода за раз, поэтому он понятия не имеет, определили ли вы Base::test< T >
в каком-то другом файле CPP. Он может работать только с тем, что есть под рукой.
Это сильно отличается от того, как дженерики работают в C#, Java и подобных языках. Лично мне нравится думать о шаблонах как о текстовом макросе, который расширяется компилятором по мере необходимости. Это заставляет меня помнить, что полное тело шаблонной функции должно быть включено в любой файл CPP, где она используется.
person
Chris Vig
schedule
29.09.2011