为什么内联模板专业化有帮助,我应该这样做吗?

时间:2012-08-01 11:57:59

标签: c++ templates function-templates

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

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

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. 内联实际上做了什么?在整个互联网上似乎是一个常见的经验法则,不应该使用内联,因为编译器“可能会以他喜欢的方式在任何情况下内联函数”。因此,如果编译器可能没有内联我声明为“内联”的函数,为什么这会起作用?

5 个答案:

答案 0 :(得分:4)

  

还有其他办法吗?将专用函数放在源文件中似乎不起作用。可能是因为我需要在标题中使用某种声明。

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

  

内联实际上做了什么?

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

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

答案 1 :(得分:3)

inline可以对一个定义规则进行一些更改。具体来说,声明inline的函数(包括函数模板的显式特化)可以在多个翻译单元中定义(假设不同翻译单元中的定义相同)并且必须定义在 odr-used 的任何翻译单元中。这与适用于功能模板(非专业化)的 odr 规则版本相同。

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

您的专业化声明如下:

template<> void f<int>(int p);

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

  

还有其他办法吗?   将专用函数放在源文件中似乎不起作用。可能是因为我   在标题中需要某种声明。

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

.h文件中声明的语法:

template <>
void f<int>(int p);

答案 4 :(得分:0)

  

还有其他办法吗?

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

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

  

内联实际上做了什么?

最佳答案已经可用:)