2013-02-07 33 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

嗯。我可以接受这是一个编译器问题,如果不是针对使用两种不同编译器的完全相同的行为,则不是语言本身。但我想这就是我将不得不忍受的东西:) –

相关问题