Неопределенные ссылки на функции-члены шаблона класса - PullRequest
7 голосов
/ 19 февраля 2012

Я хочу использовать итераторы в методе класса шаблона.Вот мой код: (testclass.h)

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first );
};

и файл testclass.cpp:

template<typename T, typename container>
void TestClassX<T, container>::gen(typename container::iterator first)
{

}

Когда я пытаюсь запустить его:

TestClassX<unsigned, std::vector<unsigned> > testx;
testx.gen(it);

Я получаю сообщение об ошибке:

Error:undefined reference to `TestClassX<unsigned int, std::vector<unsigned int, std::allocator<unsigned int> > >::gen(__gnu_cxx::__normal_iterator<unsigned int*, std::vector<unsigned int, std::allocator<unsigned int> > >)'

Я использую mingw32 4.4

Я хочу иметь класс, который может писать в разные контейнеры, такие как std :: vector, std :: list, QVector или QListвсе, что имеет итераторы в стиле STL.

Ответы [ 3 ]

10 голосов
/ 19 февраля 2012

Методы класса шаблона должны быть определены в заголовочном файле. Когда вы используете шаблонный класс, компилятор фактически компилирует версию этого класса для заданных параметров шаблона. Поэтому необходимо, чтобы тело каждого метода было доступно при включении файла заголовка.

Удалите исходный файл и включите тело в testclass.h:

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first ) {

    }
};
1 голос
/ 24 апреля 2016

Методы класса шаблона НЕ ДОЛЖНЫ быть определены в заголовочных файлах.Но если вы сделаете это, вам нужно определить отдельный модуль компиляции (например, templates.cpp) и включить файл исходного кода класса шаблона (например, #include "container.cpp" // .cpp НЕ.hpp file), тогда вам нужно определить экземпляры шаблонов, которые вы используете (например, шаблон класса Container;).Вам также необходимо определить объект для класса шаблона (например, Link).В данном конкретном случае, поскольку мы используем указатель на этот объект (например, Link *, в контейнере), нам просто нужно «объявить вперед» этот объект.

Вот полный файл template.cpp.Который вы бы скомпилировали и связали с остальным кодом.

class Link;
#include "Container.cpp"    // use the source code, not the header
template class Container<Link*>; 

Мне нравится использовать этот метод, потому что он не позволяет компилятору автоматически генерировать экземпляры класса шаблона и позволяет узнать, когда он не может его найти.

Скомпилируйте с помощью gcc, используя опцию -fno-implicit-templates.

При сборке все будет скомпилировано как обычно, но затем сборщик перекомпилирует файл templates.cpp для всех объектов, которые используют шаблон.

0 голосов
/ 10 июня 2018

Как указывалось ранее, определение должно существовать в том же модуле компиляции, когда создается экземпляр шаблона.

Лично я предпочитаю хранить определения отдельно от объявлений.
Это обеспечивает чистоту заголовочных файлов ивизуально отделяет интерфейс от реализации.

Таким образом, одно решение может быть следующим:

//TestClass.hpp

//Interface:
template<typename T>
class TestClassX
{
public:
    void gen(int a);
    //more declaraions...
}; 

//Implementations:
template<typename T>
void TestClassX<T>::gen(int a)
{
    //beautiful code
}

Вы можете разместить реализацию и интерфейс в отдельных файлах (т.е. TestClass.hpp и ITestClass.hpp соответственно).
TestClass.hpp первоначально будет #include ITestClass.hpp, а затем определит функцию, как показано в примере выше.
Тогда клиентам потребуется только #include TestClass.hpp.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...