Ошибка компоновщика «неразрешенный внешний символ»: работа с шаблонами - PullRequest
8 голосов
/ 05 декабря 2009

У меня есть шаблонный класс [Allotter.h & Allotter.cpp]:

template <typename allotType> class Allotter {
public:
 Allotter();
 quint32 getAllotment(allotType*);
 bool removeAllotment(quint32, int auto_destruct = 0);

private:
 QVector<QPair<quint32, allotType*>> indexReg;
 int init_topIndex;
};

и его использование показано как [ActiveListener.h & ActiveListener.cpp]:

class ActiveListener: public QObject {
 Q_OBJECT

public:
 ActiveListener();

private slots:
    void processConnections();
    void readFromSocket(int);

private:
 QTcpServer* rootServer;
 QSignalMapper* signalGate;
 Allotter<QTcpSocket> TcpAllotter;
};

Я не показываю полные определения, так как это не имеет значения. Проблема в том, что когда я компилирую, все файлы компилируются правильно. Файлы находятся в проекте VC ++. Раньше, когда я не использовал шаблонный подход для Allotter, все компилировалось и компоновалось нормально. Но теперь я получаю эту ошибку:

1>ActiveListener.obj : error LNK2019: unresolved external symbol "public: __thiscall Allotter<class QTcpSocket>::Allotter<class QTcpSocket>(void)" (??0?$Allotter@VQTcpSocket@@@@QAE@XZ) referenced in function "public: __thiscall ActiveListener::ActiveListener(void)" (??0ActiveListener@@QAE@XZ)
1>ActiveListener.obj : error LNK2019: unresolved external symbol "public: unsigned int __thiscall Allotter<class QTcpSocket>::getAllotment(class QTcpSocket *)" (?getAllotment@?$Allotter@VQTcpSocket@@@@QAEIPAVQTcpSocket@@@Z) referenced in function "private: void __thiscall ActiveListener::processConnections(void)" (?processConnections@ActiveListener@@AAEXXZ)

Удивительно, что конструктор ActiveListener::ActiveListener() вообще не делает никаких ссылок Allotter<QTcpSocket>::Allotter(). Вторая ссылка, однако, существует. Но я не понимаю, почему компоновщик не может разрешить этот внешний символ.

Результат сборки перед появлением ошибок:

1>Moc'ing ActiveListener.h...
1>Compiling...
1>stdafx.cpp
1>Compiling...
1>ActiveListener.cpp
1>Allotter.cpp
1>moc_ActiveListener.cpp
1>main.cpp
1>Generating Code...
1>Linking...

Я не понимаю, относится ли это к чему-либо, главным образом потому, что раньше все это прекрасно работало. Просто после использования шаблонов возникает проблема. Любая помощь будет оценена. Большое спасибо.

Ответы [ 3 ]

17 голосов
/ 05 декабря 2009

Вы не можете разбивать шаблоны на файлы .h и .cpp - вам нужно поместить полный код шаблона в файл .h.

4 голосов
/ 06 декабря 2009

Вообще говоря, рекомендуется писать код шаблона целиком внутри заголовочных файлов. Для этого есть важная техническая причина: когда вы создаете экземпляр шаблона, компилятору C ++ необходимо сгенерировать из этого шаблона код, специфичный для указанных вами параметров шаблона. Если код вашего шаблона полностью помещен в заголовки, это делается автоматически.

Это , безусловно, позволяет писать код шаблона так, как вы это делаете, с реализацией, помещенной в файлы cpp. Однако, если вы сделаете это, вам потребуется явно создать экземпляр шаблона, который вы собираетесь использовать.

В вашем случае вам нужно добавить следующую строку в файл .cpp в вашем проекте:

template class Allotter<QTcpSocket>;
1 голос
/ 05 декабря 2009

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

...