10

我有一个名为“SimObject”的类:

namespace simBase
{
    class __declspec(dllexport) SimObject: public SimSomething
    {
        public:

            template <class T>
            void updateParamValue( const std::string& name, T val );
    }
}

我有另一个名为“ITerrainDrawable”的类:

namespace simTerrain
{
    class __declspec(dllexport) ITerrainDrawable : public simBase::SimObject
    {
    }
}

这些类位于不同的库中。SimObject 在 simBase 中,ITerrainDrawable 在 simTerrain 库中。即使 ITerrainDrawable 是从 SimObject 派生的,并且我包含了 simBase 库,我也会收到链接错误:

未解析的外部符号

1>ITerrainDrawable.obj : error LNK2019: unresolved external symbol "public: void __thiscall simBase::SimObject::updateParamValue<float>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,float)" (??$updateParamValue@M@SimObject@simBase@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@M@Z) referenced in function "public: void __thiscall simTerrain::ITerrainDrawable::setTerrainSize(float)" (?setTerrainSize@ITerrainDrawable@simTerrain@@QAEXM@Z)
1>ITerrainDrawable.obj : error LNK2019: unresolved external symbol "public: void __thiscall simBase::SimObject::updateParamValue<class osg::Vec4f>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class osg::Vec4f)" (??$updateParamValue@VVec4f@osg@@@SimObject@simBase@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@VVec4f@osg@@@Z) referenced in function "public: void __thiscall simTerrain::ITerrainDrawable::setSatelliteTextureBorders(class osg::Vec2f,class osg::Vec2f)" (?setSatelliteTextureBorders@ITerrainDrawable@simTerrain@@QAEXVVec2f@osg@@0@Z)

为什么我会收到此错误?

如果我不使用模板功能,一切正常,但我需要它。

如果我将此函数移动到 simTerrain 库,它可以正常工作,但我不想使用重复的函数,因为有很多像 simTerrain 这样的库。

4

5 回答 5

15

C++ 并不真正支持模板代码的单独编译——您需要将模板的定义放在头文件中。

于 2009-12-28T12:57:09.197 回答
6

模板有两种编译模型:

  1. 包含编译模型(如包含头文件)
  2. 分离编译模型(接口与实现分离)

您可以在第二个选项的模板定义时使​​用export 关键字

export template <class T>
void updateParamValue( const std::string& name, T val ) {}

但我不确定所有编译器都支持它。

于 2009-12-28T13:46:11.250 回答
5

模板类的完整实现必须在该模板类的标头中。C++ 的 ANSI/ISO 标准允许使用export关键字将实现放在单独的编译单元中,但目前有任何编译器实际上支持这一点。

有关更多信息,请阅读此。

于 2009-12-28T13:23:22.513 回答
5

您需要指定(cpp 文件很好)模板专业化。这意味着您需要导出模板参数的所有组合,您将使用:

template __declspec(dllexport) void updateParamValue<int>( const std::string& name, T val );
template __declspec(dllexport) void updateParamValue<short>( const std::string& name, T val );
......

我在 Visual Studio 2013 中使用它并且它有效。

于 2015-03-23T06:52:45.100 回答
4

这是工作示例:

template<class T> TEST_API void foo(T)
{
    std::cout << "test";
}

template TEST_API void foo(int);
template TEST_API void foo(char);

文件 test.dll 的转储

文件类型:DLL

部分包含 test.dll 的以下导出

00000000 characteristics
4FDEF629 time date stamp Mon Jun 18 12:34:33 2012
    0.00 version
       1 ordinal base
       3 number of functions
       3 number of names

ordinal hint RVA      name

      1    0 00001032 ??$foo@D@@YAXD@Z = @ILT+45(??$foo@D@@YAXD@Z)
      2    1 00001014 ??$foo@H@@YAXH@Z = @ILT+15(??$foo@H@@YAXH@Z)
于 2012-06-18T09:43:35.637 回答