【问题标题】: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 违规行为进行抱怨”的指令正如小狗所说。

【问题讨论】:

    标签: c++ templates inline


    【解决方案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]

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-13
      • 2013-10-27
      • 1970-01-01
      • 2020-06-01
      • 2016-04-17
      • 2017-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多