g ++的一个奇怪的'未定义的'错误引用'

时间:2013-11-09 07:38:10

标签: c++ compiler-errors namespaces loader undefined-reference

请参阅下面的演示代码:

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;
}

}

testb.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,那没关系。为什么呢?

谢谢!

1 个答案:

答案 0 :(得分:2)

这是您需要显式实例化或将代码移回b.hpp的情况之一。这是因为编译debug::test::footestb.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上面指出的那样,这个帖子很好地解释了发生了什么:Why can templates only be implemented in the header file?