2013-11-09 51 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?