编译器优化消除了隐式模板实例化,从而导致链接器错误

时间:2019-05-31 09:39:37

标签: c++ templates linker-errors

我正在尝试将模板函数的定义移出头文件。

我知道,为了做到这一点,我可以使用我想从外部看到的所有类型(在链接期间)显式实例化此函数。但是,在源文件中(连同函数的定义一起),我具有所有必要类型的函数用法(隐式实例化)。该代码可以正常工作并与-O0完美链接,但无法与-O2链接。

我能够使问题最小化:

// a.cpp
#include "b.h"

int main() {
  bar<int>();
  return 0;
}
// b.h
template <class T> void bar();
// b.cpp
#include "b.h"

template <class T> void bar() {}

void foo() { bar<int>(); }

如果我用-O0和-O2编译 b.cpp ,我将在目标文件中得到一组不同的符号:

> clang++ -c b.cpp -o b.o && nm -A b.o

b.o:0000000000000000 W _Z3barIiEvv
b.o:0000000000000000 T _Z3foov

> clang++ -c b.cpp -O2 -o b.o && nm -A b.o

b.o:0000000000000000 T _Z3foov

gcc 也是如此。

看起来编译器内联了实例化函数并删除了它,因为他们看不到该函数的任何其他用法。

是否可以在不显式实例化隐式实例化模板函数的情况下将其删除?

谢谢!

UPD :这个相关问题的answer(如@ Jarod42所指出的)也回答了我的问题:根据标准,没有显式实例化就不可能做到这一点

1 个答案:

答案 0 :(得分:-1)

根据我从代码片段中得到的信息,您缺少模板功能的实际定义。您正在做的就是调用它。

您只需要定义模板功能。可能看起来像这样(根据您的情况,很可能位于b.cpp

tempate <class T>
void bar()
{
  // My function
  std::cout << "bar()" << std::endl;
}