【问题标题】:C++ Shared Library with Templates: Undefined symbols error带有模板的 C++ 共享库:未定义符号错误
【发布时间】:2010-11-04 14:09:45
【问题描述】:

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

shared.h

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

shared.cpp

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

ma​​in.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 中的“模板”内容,并将它们替换为“int”,一切正常。另外,如果我只是将模板类代码复制并粘贴到main.cpp,并且不链接到共享库,那么一切正常。

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

我正在使用带有 GCC 4.0.1 的 MacOS 10.5。

【问题讨论】:

标签: c++ templates gcc class linker


【解决方案1】:

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

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

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

这将使用 Type=int 实例化模板并将实例化的代码放在共享库中。为您需要的所有类型添加尽可能多的显式实例化。

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

【讨论】:

  • 这正是我想要的。太感谢了!供有相同问题的其他人参考:在 shared.cpp 文件的 END 处添加模板实例化行。
  • 很好,但是如果我有两个源文件,而不是像 OP 那样的一个,该怎么办?那我应该在哪里添加这些行呢?
  • @ForceBru:在任何一个中。我建议与定义模板的头文件对应的源文件。
【解决方案2】:

模板函数定义必须驻留在头文件中。将定义从 shared.cpp 移动到 shared.h。

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

【讨论】:

  • 所以不可能有一个带模板的共享库?
  • 相反,它非常容易。只需将其放在头文件中,然后共享即可。你甚至不需要编译器;)模板在实例化之前不会被编译,所以如果你将模板放在 .cpp 文件中并将其编译为共享库,模板代码就会被简单地删除。模板定义必须对用户可见。
  • 你确定吗?因为我目前正在使用一个在编译期间实例化模板的共享库。该代码对用户是不可见的,但可以使用。当您混合需要生成的专业化和已经生成的其他专业化时,可能会出现编译问题。但除此之外,它确实工作正常。使用 g++ 和 msvc 测试。
  • 规则例外:可以在.cpp文件中定义模板函数——只要满足.cpp文件实例化模板。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2010-11-09
      • 1970-01-01
      • 1970-01-01
      • 2018-04-14
      • 1970-01-01
      • 1970-01-01
      • 2021-03-08
      • 2011-02-28
      • 2016-10-16
      相关资源
      最近更新 更多