4

我想提供一个提供模板代码的库。但是当我能猜到我的模板的不同常用类型的用法时,我也想尽可能地保留这段代码(生成的代码)的所有权。这是我正在尝试做的一个例子:

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

当我使用我的图书馆时:

主文件

#include <lib1.h>

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

编译:

g++ main.cpp -l1

在这里,我希望符号 print_me<0>() 和 print_me<1>() 是从 lib1.so 定义和使用的,并且 print_me<2>() 定义并用于我的可执行文件(使用 nm --defined-only 检查)。但似乎并非如此!0 和 1 的符号在 lib1.so 中定义良好,但属于符号。并且再次在我的可执行文件(0、1和2)中重新定义,弱。这意味着我的可执行文件的 0 和 1 代码取自 main.cpp,这不是我想要的(我检查了 main.cpp 中的规范)。

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

4

3 回答 3

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)in的定义lib1.h代替其声明,只要在专用版本中找不到它就会使用它。

于 2014-01-31T15:15:30.407 回答
3

C++11 解决方案:使用外部模板。只需将这些字符串添加到您的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>();

于 2014-02-01T12:00:08.797 回答
2

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

//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<2>() 的无用错误。使用这个框架(C++11)会更好(恕我直言):

//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 做一个嵌套函数来使它更好。

于 2014-01-31T14:49:13.323 回答