假设我有一个在f(int)中声明并在<int dim>中定义的非类型模板函数template.h(参数template.cpp)。在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);

附注:我使用g++和clang++和clang++ -o tmpl template.cpp main.cpp命令进行编译。

最佳答案

如果将函数声明为inline,则编译器确实不必生成非内联版本,除非请求了指向该函数的指针,或者它决定在某个调用站点上最好不内联(不必要求编译器始终内联)即使您声明inline)。

现在要内联函数,编译器需要在编译调用站点时查看函数的定义。但是您在.cpp中定义了该函数,并尝试从其他.cpp调用它。因此,编译器看不到定义,而是尝试调用非内联版本。但是它不是生成的,因为您告诉编译器内联函数,并且在需要非内联版本的情况下没有看到任何用处,因此它没有生成。如果不声明inline,则默认值为extern,并且始终生成非内联版本。然后,您声明了要生成的显式实例,这样就可以了。

正如编译器不必内联一样,它不必生成extern版本。我怀疑有一些随机差异会导致编译器在一种情况下而不是另一种情况下生成非内联实例。在任何一种情况下,如果您声明内联,则必须在 header 中定义它,除非您仅从一个来源实际使用它(例如,有时私有(private)方法可以内联并在实现中定义,因为您仅在那个源中使用它们)文件)。

10-07 19:10
查看更多