我想提供一个提供模板代码的库。但是,当我能猜出我的模板的不同常用类型的用法时,我还想尽可能保留此代码(生成代码)的所有权。这是我想要做的一个例子:
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的编译时说某些符号已在某处定义并且不需要添加这些符号?
答案 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做一个嵌套函数,使其更好。