强制定义库中C ++模板实例的符号

时间:2014-01-31 13:58:00

标签: c++ templates symbols nm

我想提供一个提供模板代码的库。但是,当我能猜出我的模板的不同常用类型的用法时,我还想尽可能保留此代码(生成代码)的所有权。这是我想要做的一个例子:

lib1.h

#include <iostream>

template<int N>
void print_me() {
    std::cout << "I am function number " << N << std::endl;
}

lib1.cpp

#include "lib1.h"

/* Force symbols to be defined here. */
template void print_me<0>();
template void print_me<1>();

我使用以下方式编译我的库:

  

g ++ -shared -fPIC lib1.cpp -o lib1.so

当我使用我的库时:

的main.cpp

#include <lib1.h>

int main() {
    print_me<0>();
    print_me<1>();
    print_me<2>();
}

编译:

  

g ++ main.cpp -l1

我希望在lib1.so和print_me&lt; 2&gt;()中定义并使用符号print_me&lt; 0&gt;()和print_me&lt; 1&gt;(),并将其用于我的可执行文件(使用nm检查 - 定义只)。但似乎事实并非如此! 0和1的符号在lib1.so中定义良好,但作为符号。并且在我的可执行文件(0,1和2)中再次重新定义,弱。这意味着我的可执行文件的0和1的代码取自main.cpp,这不是我想要的(我在main.cpp中使用规范检查)。

有没有一种方法(例如在lib1.h中)在main.cpp的编译时说某些符号已在某处定义并且不需要添加这些符号?

3 个答案:

答案 0 :(得分:3)

我会使用模板专业化来分离实现和界面:

lib1.h:

#include <iostream>
template <int T> void print_me(void);
template <> void print_me<0>(void);
template <> void print_me<1>(void);

lib1_internal.h(注意:这不需要披露):

#include <iostream>

template<int N>
void print_me_internal() {
    std::cout << "I am function number " << N << std::endl;
}

lib1.cpp:

#include "lib1.h"
#include "lib1_internal.h"

template <> void print_me<0>() {
  print_me_internal<0>();
}
template <> void print_me<1>() {
  print_me_internal<1>();
}

你的main.cpp会正确导致链接器错误:

$ g++ main.cpp -L. -l1
/tmp/ccZSDqkp.o: In function `main':
main.cpp:(.text+0xf): undefined reference to `void print_me<2>()'
collect2: ld returned 1 exit status

只需在template <int T> void print_me(void)中添加lib1.h的定义来代替其声明,只要在专门版本中找不到它,就会使用它。

答案 1 :(得分:3)

C ++ 11解决方案:使用extern templates。只需将这些字符串添加到main.cpp文件中:

extern template void print_me<0>();
extern template void print_me<1>();

因此,您告诉编译器不要在print_me中实例化main.cpp函数模板(对于模板参数0和1)。因此,链接器应在其他翻译单元中搜索void print_me<0>();void print_me<1>();的定义。

答案 2 :(得分:1)

您必须在头文件中隐藏实现。

//lib1.h    
template<int N>
void print_me();

//lib1.cpp
#include <iostream>
#include "lib1.h"
template <int printme>
void print_me()
{
  std::cout << printme << std::endl;
}

template void print_me<0>();
template void print_me<1>();

正在发生的是模板通常如何使用:它们仅在需要时构建(否则你必须为所有整数构建print_me),因此他们在软件运行时找出实现(这就是为什么它会减慢的原因)编译时间太多,它为每个使用模板的编译单元重建类。只要您具有模板的定义,就可以为所需的任何参数构建它。这是隐藏.cpp文件中的定义半有效的少数情况之一,但最终用户通常会为print_me&lt; 2&gt;()获得一个无用的错误。使用这个框架(C ++ 11)会更好(imho):

//lib1.h
#include <type_traits>
template<int N>
typename std::enable_if<N == 1 || N == 0>::type print_me();

//lib1.cpp
#include <iostream>
#include "lib1.h"

template<int N>
typename std::enable_if<N == 1 || N == 0>::type print_me()
{
  std::cout << N << std::endl;
}

template void print_me<0>();
template void print_me<1>();

现在错误是“没有用于调用print_me()的匹配函数”这稍微好一点......你可以用static_assert做一个嵌套函数,使其更好。