将 inline 关键字与模板一起使用是不是有意义?

Posted

技术标签:

【中文标题】将 inline 关键字与模板一起使用是不是有意义?【英文标题】:Does it make any sense to use inline keyword with templates?将 inline 关键字与模板一起使用是否有意义? 【发布时间】:2012-05-19 02:58:30 【问题描述】:

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


编辑:我想接受这两个答案,但这是不可能的。为了结束这个问题,我接受 Sebastian Mach 的回答,因为它获得了最多的选票,而且他在形式上是正确的,但正如我在 cmets 中提到的,我认为 Puppy 的和组件 10 的答案也是正确的,从不同的角度来看。

问题在于 C++ 语义,在 inline 关键字和内联的情况下并不严格。 Sebastian Mach 说“如果你是认真的就写内联”,但 inline 的实际含义尚不清楚,因为它从最初的含义演变为“停止编译器对 ODR 违规行为进行抱怨”的指令正如小狗所说。

【问题讨论】:

【参考方案1】:

这不是无关紧要的。不,不是每个函数模板默认都是inline。该标准甚至在 Explicit specialization ([temp.expl.spec])

中对此进行了明确说明

具备以下条件:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h(取自显式专业化):

#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,不会收到错误,但它们仍然不是@987654329 @。对于完整的特化,即只使用已知类型的特化,你不能省略它。

建议的经验法则:写inline,如果你是认真的,请保持一致。它让你更少考虑是否仅仅因为你可以。 (此经验法则符合Vandevoorde's/Josuttis's C++ Template: The Complete Guide)。

【讨论】:

真的可以写出来。但这并不意味着内联,即使它看起来像那样。 Vandevoorde 和 Josuttis 在 C++ 模板:完整指南 中也明确说明了这一点 显式特化不是模板。 @DeadMG:然而,在查找时,普通函数优于完全专业化,所以如果它们不是模板,也不是非模板,那么它们是什么? 这个答案不正确。模板的显式特化是一个函数,而不是模板。该函数不会变成inline,只是因为专门化的模板标有inline。所以模板上的inline 完全无关紧要。该函数是否应该是 inline 与它通过模板专业化生成无关(并且有比这更好的答案,即何时使用 inline)。 @Puppy 下面的答案是正确的,这个不是。在模板上添加inline 是无关紧要的,clang-tidy 实际上会删除它。 此外,该示例仅展示了正常功能的 ODR 问题(该行为与模板无关)。为了尝试表明inline 并非无关紧要,该示例应涵盖明确专门化template&lt;&gt; void f&lt;&gt;(int) 没有 inline 关键字的情况。但即便如此,更改模板上的inline 说明符也没有任何区别,因为是否标记模板inline 无关紧要。【参考方案2】:

这无关紧要。所有模板都已经是inline——更不用说截至 2012 年,inline 关键字的唯一用途是阻止编译器抱怨 ODR 违规。您是绝对正确的 - 您当前的编译器将知道自己内联什么,甚至可能在翻译单元之间这样做。

【讨论】:

标准没有规定所有模板都是内联的。 @phresnel:但是模板与inline标记的函数具有相同的语义(也就是说,可以将多个等效定义传递给链接器,链接器将选择一个)。这不是内联,是 inline 关键字的真正功能。 @BenVoigt:我知道inline 的 ODR 含义。也许可以在下面(或上面,取决于选择的排序)看看我的答案。对于非专业模板,你当然是对的,但形式上不一样。 @DeadMG:C++中没有要求函数模板必须在头文件中实现;它可以在任何地方实施。为了反映这一点,我倾向于建议标记inline应该是内联的。它通常没有区别,但在标准语言中,它们是不一样的,而且它们也不都是内联的。我接受你的立场,说“这无关紧要”,但根据标准,并非所有模板都是内联的,只有作为 C++ 用户的你,它们看起来好像。 您对明确专业化不是模板的公认答案的评论(很明显被告知之后,当然....)也许是最有帮助的事情在本页。您是否介意将其也添加到您的答案中?【参考方案3】:

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

inline 与模板一起使用曾经是一种(较差的)解决方法,即每个编译单元都会为同一个模板类创建一个单独的对象,这会导致链接时出现重复问题。通过使用inline(我认为),名称修饰的效果不同,它在链接时解决了名称冲突,但以大量臃肿的代码为代价。

Marshall Cline explains it here 比我做得更好。

【讨论】:

@Xeo:以前不是这样的。在这里查看:gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/… 我认为最近发生了变化,这就是我用过去时态说话的原因。 @Xeo:你能指出标准中声明函数模板总是内联的部分吗?因为,他们不是。 @phresnel:有趣,我可以发誓我已经在标准中读到了。也许我把它与函数模板不受 ODR (§14.5.5.1 p7 &amp; p8) 的事实混为一谈。糟糕,我删除了错误的评论。 @Component 10 为什么你认为这是解决编译问题的糟糕方法 编译器可能会提供使内联的标志不仅仅是一个提示(例如,clang 有-finline-hint-functions)。不过,使用这些标志是否是个好主意是另一个问题。【参考方案4】:

这是 C++ 标准所说的:

[dcl.inline/1]

内联说明符只能应用于变量或函数的声明。

【讨论】:

以上是关于将 inline 关键字与模板一起使用是不是有意义?的主要内容,如果未能解决你的问题,请参考以下文章

将 Psyco 与 django 一起使用是不是有意义?

将存储库模式与文档数据库一起使用是不是有意义?

将 DAO 模式与 ORM 系统一起使用是不是有意义? [关闭]

实体框架 4:为所有实体创建单个图表是不是有意义?

在Web Api中使用ViewModel是否有意义?

C ++内联方法实现[重复]