Сначала вы должны понять механизм шаблонов.Шаблоны не компилируются, они создаются при их использовании, а затем их экземпляр компилируется.Таким образом, компилятор должен иметь полное определение шаблона в каждом модуле, используя функцию шаблона, чтобы сначала создать их экземпляр в соответствии с переданными вами параметрами.
Для решения вашей проблемы есть три решения, но выПосмотрим, что они оба приведут к одному и тому же результату.Либо вы реализуете свои шаблоны целиком в своем заголовочном файле внутри определения класса (мы используем суффикс их с .hxx вместо .h, чтобы уточнить, что они содержат определения шаблонов):
// Foo.hxx
#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
public:
template <class T>
void bar(const T& t) {
t.doSomething();
}
};
#endif
Или выможно вывести определение из класса, но все еще в заголовочном файле:
// Foo.hxx
#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
public:
template <class T>
void bar(const T&);
};
template <class T>
void Foo::bar(const T& t) {
t.doSomething();
}
#endif
Наконец, вы можете реализовать тела методов шаблона во внешнем файле (с той же причиной префиксом .cxx).Он будет содержать тела методов, но не будет содержать «Foo.hxx».Вместо этого это «Foo.hxx», который будет включать «Foo.cxx» после определения класса.Таким образом, когда компилятор разрешает директиву #include, он находит все определение шаблона в том же модуле, позволяя ему создать его экземпляр:
// Foo.hxx
#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
public:
template <class T>
void bar(const T&);
};
#include "Foo.cxx"
#endif
// Foo.cxx
template <class T>
void Foo::bar(const T& t) {
t.doSomething();
}
Выбор между этими тремя способами реализации шаблонов довольновопрос читабельности (и вкуса).
Второе и третье эквивалентны с точки зрения сгенерированного кода, но я бы предпочел не использовать файловое решение cxx, потому что оно часто приводит к глупым ошибкам, когда вы забываете инвертировать включение.
Кроме того, известные библиотеки C ++, такие как STL или Boost, предлагают свой код только в заголовочных файлах, что является признаком хорошего дизайна.Используя внешнее определение внутри заголовков, вы уточняете определение вашего класса.Вы также запрещаете компилятору автоматически включать методы, что иногда может привести к плохим результатам, согласно Хербу Саттеру http://www.gotw.ca/gotw/033.htm