具有模板的C ++共享库:未定义符号

我正在尝试使用模板类链接到共享库,但这给了我“未定义符号”错误。 我将问题压缩为大约20行代码。

共享的

template <class Type> class myclass {
  Type x;
public:
  myclass() { x=0; }
  void setx(Type y);
  Type  getx();
};

共享的

#include "shared.h"
template <class Type> void myclass<Type>::setx(Type y) { x = y; }
template <class Type> Type myclass<Type>::getx() { return x; }

main.cpp

#include <iostream>
#include "shared.h"
using namespace std;

int main(int argc, char *argv[]) {
   myclass<int> m;
   cout << m.getx() << endl;
   m.setx(10);
   cout << m.getx() << endl;
   return 0;
}

这是我编译库的方式:

g++ -fPIC -c shared.cpp -o shared.o
g++ -dynamiclib -Wl,-dylib_install_name -Wl,libshared.dylib -o libshared.dylib shared.o

和主程序:

g++ -c main.cpp
g++ -o main  main.o -L. -lshared

仅得到以下错误:

Undefined symbols:
"myclass<int>::getx()", referenced from:
  _main in main.o
  _main in main.o
"myclass<int>::setx(int)", referenced from:
  _main in main.o

如果我删除shared.h/cpp中的“模板”内容,并仅用“整数”替换它们,那么一切正常。 另外,如果我只将模板类代码复制并粘贴到main.cpp中,并且不链接到共享库,那么一切也将正常运行。

如何获得这样的模板类以通过共享库工作?

我将MacOS 10.5和GCC 4.0.1一起使用。

nolk asked 2020-08-12T04:43:22Z
4个解决方案
41 votes

除了其他答案,您还可以显式实例化模板类。 仅当您事先知道模板参数可以假定的类型时,这才有用。 您可以在库中使用所有这些类型实例化模板。

对于您要编译的示例,只需将以下内容添加到shared.cpp的末尾:

// Instantiate myclass for the supported template type parameters
template class myclass<int>;
template class myclass<long>;

这将使用Type = int实例化模板,并将实例化的代码放置在共享库中。 为所需的所有类型添加所需数量的显式实例化。

同样,如果希望能够使用任意Type参数实例化模板,则必须将定义添加到头文件中,以便编译器在其他编译单元中实例化模板时知道模板的源代码。

Juliano answered 2020-08-12T04:43:42Z
20 votes

模板函数定义必须位于头文件中。 将定义从shared.cpp移到shared.h。

因此,您不能将其编译为共享库,然后链接到它。 就是那样行不通。

rlbond answered 2020-08-12T04:44:06Z
6 votes

您还需要在头文件中包括模板类的实现。 这是C ++中模板的约束。 因此,要么包含来自main(#include)的shared.cpp,要么只是将代码从shared.cpp中移到shared.h中

Cătălin Pitiș answered 2020-08-12T04:44:27Z
2 votes

编译器必须查看模板的所有代码,因此它可以为要使用的实际类型生成适当的代码。因此,您应该将所有代码放在.h中。 文件。

nos answered 2020-08-12T04:44:49Z
translate from https://stackoverflow.com:/questions/1022623/c-shared-library-with-templates-undefined-symbols-error