共享库中未使用的模板函数

时间:2010-08-05 17:16:21

标签: c++ templates

我在用C ++编写的共享库中有一个模板函数(该函数不会在库中的任何地方调用,所以不应该生成它,我错了吗?)[g ++,Linux]

我尝试在应用程序中使用此模板函数但编译器给出了链接错误。我使用objdump搜索了函数但是我无法在.so中看到函数 有没有办法解决这个问题?

5 个答案:

答案 0 :(得分:6)

模板函数属于库头,它们不在DLL共享库中编译。因此,将所有模板函数移动到标题中,并在应用程序中包含该标题。

答案 1 :(得分:6)

最简单的方法是将所有模板代码移动到头文件中(如其他答案中所述) 但是这不是唯一的解决方案。

模板不是实际功能。

当存在函数的实例化时,模板成为函数。这可以隐式或明确地完成。无论何时使用该函数,都存在隐式实例。但您也可以明确地实现模板功能。

因此,您应该能够在共享库中链接模板函数的任何实例化版本。

头文件,因此我们遵守一个定义规则。

// tt.h
template<typename T>
int doStuff(Tconst &t);

源文件:

// tt.cpp
#include "tt.h"
template<typename T>
int doStuff(Tconst &t)
{
    return 4;
}

void plop()
{
    int x = 6;
    // implicit instanciation of doStuff<int>(int const&);
    doStuff(x);
}

// explicit instanciation of template
template int doStuff<float>(float const&);

如果我将上述内容编译成共享库 然后会有两个可用的doStuff()方法。

  • doStuff&lt; int&gt;(int const&amp;)//隐式instanciation
  • doStuff&lt; float&gt;(float const&amp;)// explit instanciation
  

g ++ -shared -o tt.so tt.cpp

现在,如果我们有一个seprate文件,我们链接到共享库:

// main.cpp
#include "tt.h"

int main()
{
    doStuff(5);   // doStuff<int>()
    doStuff(6.0f); // doStuff<float>()
}
  

g ++ main.cpp t.so

即使main看不到任何模板代码,编译也很好。

答案 2 :(得分:1)

模板很难由编译器开发人员实现,因此,大多数C ++编译器实际上都要求您将模板代码放在头文件中,甚至是完整的类实现(尽管有一些例外和技巧可以避免这种情况)。

对于您的情况,您需要做的就是将您的功能模板移动到头文件(可能包含其他功能模板),并在需要时将其导入。

希望有所帮助。

答案 3 :(得分:0)

您要使用的功能需要在您的库或代码中的某处实例化。您的编译器应该在程序代码中为您生成实例化,除非原型被声明为extern。听起来你想要在库中显式实例化该函数。在库中的一个源文件中,您只需添加如下行:

template return_type function_name(param_type,param_type);

并且应该显式生成函数的代码。

有关显式实例化的更多信息: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/explicit_instantiation.htm

答案 4 :(得分:0)

前段时间我发现自己处于相同的状况,所以我对此进行了调查。基本上模板不会产生任何目标代码,它们只是编译器的定义。当您实例化std::list<Foo> l之类的对象时,编译器将为Foo对象列表生成实例和专用代码。

这导致两个后果:

  • 不可能将模板类代码写入专用的.cpp文件(就像你对普通模块所做的那样),因为你事先并不知道你需要实例化哪些数据类型;
  • 使用std::list<Foo>作为数据类型的两个.cpp文件将生成相同可执行代码的副本。

第二点在链接阶段使事情变得困难,因为链接器应该处理双重定义。可能的链接策略是为每个目标代码保留一份副本。更聪明的链接器可能会尝试优化,但这会带来很大的复杂性。

我想这就是为什么gcc编译C ++需要很长时间,而C语言的速度要快得多。