2013-11-09 31 views
1

见下面我的演示代码:A怪 '未定义参考' 错误使用g ++

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 

什么问题?

如果我把主函数放在b.cpp中并编译b.cpp,没关系。为什么?

谢谢!

+0

简短的回答,编译器永远不会实例化'测试:: foo '这样的功能在任何时候都不存在。为什么它不能实例化?因为完整的定义不可用。 – greatwolf

回答

2

这是您需要明确实例化或将代码移回b.hpp的情况之一。这是因为在编译testb.cpp时,debug::test::foo的实现不可见,编译器无法知道在编译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?