2013-02-07 32 views
1

假設我有一個在template.h中聲明並在template.cpp中定義的非類型模板函數f(int)(參數<int dim>)。在template.cpp我進一步爲dim = 2添加了一項專業化,然後我明確地實例化了dim = 1dim = 2的模板函數。爲什麼我不能使用單個非類型參數內聯顯式實例化模板函數?

該文件編譯罰款,但在連接過程中,我得到一個錯誤:

Undefined symbols for architecture x86_64: 
    "void f<2>(int)", referenced from: 
     _main in main-2AW7ED.o 
ld: symbol(s) not found for architecture x86_64 

但是,如果我刪除模板專業化inline關鍵字(見下文標記),整個事情按預期工作。因此,我的問題來了:

爲什麼inline不適用於專用模板,當它適用於基本模板時,其他所有內容編譯和工作正常?

main.cpp中

#include <iostream> 
#include "template.h" 

using namespace std; 

int main(int, char**) 
{ 
    f<1>(456); 
    f<2>(789); 
} 

template.h

template <int dim> void f(int src); 

template.cpp

#include <iostream> 
#include "template.h" 

using namespace std; 

template <int dim> inline 
void f(int src) 
{ 
    cout << "src = " << src << endl; 
    cout << "dim (template) = " << dim << endl; 
} 

template <> inline // <== if I remove this "inline", everything works as expected 
void f<2>(int src) 
{ 
    cout << "src = " << src << endl; 
    cout << "dim (fixed) = " << 2 << endl; 
} 

template void f<1>(int); 
template void f<2>(int); 

P.S .:我用g ++和clang ++來編譯命令clang++ -o tmpl template.cpp main.cpp

+0

爲什麼你還沒有在template.h中的聲明上定義'inline'? –

+0

這實質上是一個ODR違規行爲。 –

+0

@TonyD從http://www.parashift。com/C++ - faq-lite/where-to-put-inline-keyword.html和其他來源我知道我只需要把它放在一個位置。 –

回答

3

如果函數聲明inline,編譯器必須除非指針功能要求不產生非共線版本,或者決定,在某些調用位置將是最好不要內聯它(編譯即使您聲明inline也不需要始終內聯)。

現在爲了內聯函數,編譯器需要在編譯調用站點時看到函數的定義。但是您在.cpp中定義了該函數,並試圖從不同的.cpp中調用該函數。因此,編譯器而不是查看定義並嘗試調用非內聯版本。但它並沒有生成,因爲你告訴編譯器內聯函數,並且沒有看到需要非內聯版本的任何用處,所以它不會生成它。如果您未聲明inline,則默認值爲extern,並始終生成非內聯版本。並且你聲明瞭你想要生成的顯式實例,所以那些實例就會生成。

正如編譯器不必內聯,它不必生成外部版本。我懷疑有一些隨機差異導致編譯器在一種情況下生成非內聯實例,而不是在另一種情況下。無論是哪種情況,如果你聲明瞭一些內聯的東西,它必須在頭文件中定義,除非你只是從一個源頭實際使用它(例如,有時私有方法可以內聯並在實現中定義,因爲你只在那個中使用它們文件)。

+0

但是,爲什麼它適用於非專業模板而不是專用模板? –

+0

@MichaelSchlottke:我更新了答案;我真的認爲這是編譯器邏輯的缺陷,而不是任何規則。 –

+0

嗯。我可以接受這是一個編譯器問題,如果不是針對使用兩種不同編譯器的完全相同的行爲,則不是語言本身。但我想這就是我將不得不忍受的東西:) –

相關問題