在模板中使用内联关键字是否有意义?


119

由于模板是在标头中定义的,并且编译器能够确定内联函数是否有利,因此有意义吗?我听说现代编译器更了解何时内联函数,而忽略了inline提示。


编辑:我想接受两个答案,但这是不可能的。为了解决这个问题,我接受phresnel的答案,因为它获得了最多的选票,而且他在形式上是正确的,但是正如我在评论中提到的那样,从不同的角度来看,我认为PuppyComponent 10的答案也是正确的。

问题出在C ++语义上,在inline关键字和内联的情况下并不严格。phresnel说“如果要用内联写,就直接写内联”,但是实际上含义inline并不明确,因为它从其原始含义演变成一个指令,如Puppy所说,该指令“阻止对ODR违规行为的争论” 。

Answers:


96

这不是无关紧要的。而且,inline默认情况下,并非每个功能模板都是默认的。在显式专业化中,该标准甚至是明确的([temp.expl.spec])

具有以下内容:

抄送

#include "tpl.h"

抄送

#include "tpl.h"

tpl.h(摘自Explicit Specialization):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

编译,等等:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

未公开inline的时候做的显式实例也可能导致的问题。

因此,总而言之:对于非完全专业化的功能模板,即那些至少带有一种未知类型的模板,您可以省略inline,并且不会收到错误,但实际上不是inline。对于完全专业化,即仅使用已知类型的专业化,您不能忽略它。

拟议的经验法则:写下inline您的意思并保持一致。它使您不必再因为仅仅可以而思考。(此经验法则符合Vandevoorde / Josuttis的C ++模板:完整指南)。


2
有人写过,是真的。但这并不意味着内联,即使看起来像那样。Vandevoorde和Josuttis在C ++模板中
Sebastian Mach

43
显式专业化不是模板。
小狗

2
@DeadMG:在查找时,一般功能要比完全专业化更受欢迎,因此,如果它们既不是模板,也不是非模板,那么它们又是什么呢?
塞巴斯蒂安·马赫

13
这个答案是不正确的。模板的显式专门化是函数,而不是模板。该功能并inline不仅仅是因为专用模板标记有inline。所以inline在模板上是完全不相关的。该功能是否应该与inline通过模板专门化生成的功能无关(并且比使用该地址时要好得多的答案inline)。@Puppy在下面的答案是正确的,这是不正确的。添加inline模板是无关紧要的,clang-tidy实际上将其删除。
gnzlbg

6
此外,该示例仅展示了正常功能的ODR问题(与模板无关的行为)。为了试图表明 inline没有无关,示例应包括明确专业的情况下template<> void f<>(int) {} 没有inline关键字。但是即使那样,更改inline模板上的说明符也没有任何区别,因为是否标记模板inline无关紧要。
gnzlbg

34

没关系 所有模板都已经inline-更不用说从2012年开始,该inline关键字的唯一用途是阻止编译器抱怨ODR违规。您是完全正确的-您当前的编译器将知道自己内联什么,甚至在翻译单元之间也可以这样做。


11
该标准未声明所有模板都是内联的。
塞巴斯蒂安·马赫

16
@phresnel:但是模板与inline标记功能具有相同的语义(也就是说,可以将多个等效定义传递给链接器,链接器将选择一个)。那不是内联的,是inline关键字的真正功能。
Ben Voigt 2012年

2
@BenVoigt:我了解的ODR含义inline。也许可以在下面(或上面,取决于所选的排序方式)窥见我的回答。对于非专业的模板,您当然是对的,但是从形式上来说并不相同。
塞巴斯蒂安·马赫

3
@DeadMG:C ++中没有要求必须在头文件中实现功能模板;它可以在任何地方实现。为了反映这一点,我倾向于建议标记inline应该内联的内容。通常没有什么区别,但是在标准语言中,它们是不相同的,并且它们也不都是内联的。我接受您的立场,说“无关紧要”,但是按照标准,并非所有模板都是内联的,仅对于您(作为C ++用户)而言,它们看起来就好像。
塞巴斯蒂安·马赫2013年

7
您对公认的明确的专业化不是模板的回答(当然,被告知很明显……),这可能是此页面上最有用的事情。您还可以将其添加到答案中吗?
Kyle Strand

6

如您所建议,inline它只是对编译器的提示,仅此而已。它可以选择忽略它,或者实际上选择不标记为内联的内联函数。

使用inline与曾经是变圆了这个问题,每个编译单元将创建一个单独的对象为同一模板类的(差)的方式模板,然后会导致在链接时重复的问题。通过使用inline(我认为),名称改写可以实现不同的效果,从而在链接时绕过名称冲突,但代价是代码过于blo肿。  

马歇尔·克莱恩(Marshall Cline)在这里尽我所能解释


@Xeo:以前并非如此。在这里检查:gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/…我认为这是最近才改变的,这就是为什么我用过去时进行讨论。
组件12年

2
@Xeo:您​​能指出标准的那一部分,指出功能模板始终是内联的吗?因为,它们不是。
塞巴斯蒂安·马赫

@phresnel:有趣的是,我可以发誓我已经在标准中阅读了。也许我将其与功能模板免于ODR(§14.5.5.1 p7 & p8)的事实混为一谈。不好,我删除了错误的评论。
Xeo 2012年

@Component 10为什么您认为解决编译问题的方法很糟糕
Kapil
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.