1

请参阅下面的演示代码:

b.hpp:

#ifndef B_HPP
#define B_HPP

namespace debug {
class test {
public:
  template <class T> void foo(T a); 
private:
  int a;
};
}
#endif

b.cpp:

#include <iostream>
#include "b.hpp"

namespace debug {

template <class T>
void test::foo(T a) {
  std::cout << "debug" << std::endl;
}

}

测试b.cpp:

include "b.hpp"

int main(int agrc, char *argv[])
{
  debug::test a;
  int c = 5;
  a.foo(c);
  return 0;
}

我用它编译

g++ -std=c++11 testb.cpp b.cpp'

并得到一个错误:

/tmp/ccnjR5S4.o: In function `main':
testb.cpp:(.text+0x1c): undefined reference to `void debug::test::foo<int>(int)'
collect2: error: ld returned 1 exit status

有什么问题?

如果我把 main 函数放在 b.cpp 中并编译 b.cpp 就可以了。为什么?

谢谢!

4

1 回答 1

2

这是您需要显式实例化或将代码移回b.hpp. 出现这种情况是因为编译时 的实现debug::test::foo不可见testb.cpp,并且编译器无法知道编译时可能需要什么b.cpp

要显式实例化debug::test::foo<int>,请将以下行添加到b.cpp

#include <iostream>
#include "b.hpp"

namespace debug {

template <class T>
void test::foo(T a) {
  std::cout << "debug" << std::endl;
}

// Explicitly instantiate test::foo<int>
template void test::foo<int>(int);   // <-- add this line

}

或者,如果您不知道此模板可能被实例化的所有方式,请将其定义移回标题中的类定义中。丑陋,但它会工作。

一些编译器会进行交叉编译单元模板实例化,但正如您所发现的,g++ 不是其中之一。(至少,不像我的系统上配置的那样。)

编辑:正如@juanchopanza 上面指出的那样,这个线程很好地解释了正在发生的事情: 为什么模板只能在头文件中实现?

于 2013-11-09T08:44:25.940 回答