1

模板特化的问题在于它们被视为普通函数,因为在任何地方都不再使用模板参数。

因此,如果将以下代码放在头文件中,它首先会起作用。

template <typename foo>
void f(foo p)
{
  std::cout << "f one" << std::endl;
}

template <>
void f<int>(int p)
{
  std::cout << "f two" << std::endl;
}

但是,如果标头包含在两个文件中,这将停止工作。在这种情况下,我得到的错误(使用 VS2010)是:

templateordering.obj : error LNK2005: "void __cdecl f<int>(int)" (??$f@H@@YAXH@Z) already defined in othertu.obj

这可以通过使用许多其他问题中提到的inline关键字来解决。

template <>
inline void f<int>(int p)
{
  std::cout << "f two" << std::endl;
}

现在这对我提出了两个问题:

  1. 有没有其他方法可以做到这一点?将专门的功能放在源文件中似乎不起作用。可能是因为我需要在标题中进行某种声明。
  2. 内联实际上是做什么的?不应该使用 inline 似乎是整个互联网的普遍经验法则,因为编译器“在任何情况下都可能以他喜欢的方式内联函数”。因此,如果编译器可能不会内联我声明为“内联”的函数,为什么会这样呢?
4

5 回答 5

4

有没有其他方法可以做到这一点?将专门的功能放在源文件中似乎不起作用。可能是因为我需要在标题中进行某种声明。

您需要在标头中声明特化,就像任何其他函数一样。是在标题中内联定义它,还是在(恰好一个)源文件中定义它取决于您;再次,就像任何其他功能一样。inline正如您所说,如果您确实在标题中定义它,则必须声明它。

内联实际上是做什么的?

通常,单定义规则要求函数在程序的一个翻译单元中定义。实际上,这意味着您不能在标题中定义函数,因为标题旨在包含在多个翻译单元中。

但是,有时您希望或需要在头文件中定义函数 - 例如,某些编译器只有在可以看到定义时才能内联函数调用。关键字放宽了规则,因此inline您可以在多个翻译单元中定义函数,只要所有定义相同。

于 2012-08-01T12:06:35.200 回答
3

inline启用对单一定义规则的一些更改。具体来说,声明的函数(包括函数模板的显式特化)inline可以在多个翻译单元中定义(前提是不同翻译单元中的定义相同),并且必须在使用它的任何翻译单元中定义。这是适用于函数模板(未专门化)的相同版本的odr规则。

您要么必须在一个翻译单元中定义您的专业化(并在其他翻译单元中使用它之前声明它),或者您可以将定义保留在头文件中,但将其设为inline.

您的专业声明如下所示:

template<> void f<int>(int p);
于 2012-08-01T12:05:05.773 回答
1

如果您从两个或多个文件中使用相同类型的函数,则函数将在每个文件中定义。这与在包含在多个源文件中的头文件中具有非模板函数定义相同。

将函数标记为inline向编译器提示它可以“内联”该函数,即将函数体直接放在调用函数的位置。这意味着该函数实际上并未定义。编译器还可以决定内联函数,在这种情况下,inline关键字的行为类似于static关键字。

于 2012-08-01T12:04:30.907 回答
0

有没有其他方法可以做到这一点?将专门的功能放在源文件中似乎不起作用。可能是因为我需要在标题中进行某种声明。

是的,如果您将 的声明和定义分开f<int>,那应该可以解决链接器错误。

.h 文件中声明的语法:

template <>
void f<int>(int p);
于 2012-08-01T12:07:34.777 回答
0

有没有其他方法可以做到这一点?

template <>
static void f<int>(int p)
{
  std::cout << "f two" << std::endl;
}

或拥有它们inline,但使用特殊的编译器标志(如果可用)来抑制实际的内联

内联实际上是做什么的?

最佳答案已经可用:)

于 2012-08-01T12:18:38.010 回答