C++11兼容的编译器是否总是忽略inline提示?

6

阅读一个旧答案关于何时应该为函数/方法编写关键字“inline”?,其中说:

据说内联提示编译器您认为该函数应内联。这在1998年可能是正确的,但十年后编译器不需要这样的提示。更不用说人类在优化代码方面通常是错的,所以大多数编译器直接忽略了这个“提示”。

这个答案是2009年发布的,所以我想最终弄清楚:

  1. 现代的与c++11兼容的编译器是否始终忽略用户指定的inline提示并自动执行此操作?
  2. inline提示是否仅保留提供向后兼容性?
  3. 如果 1. 不是那么这个答案是不正确的吗?

1
@iammilind,所以你的问题的答案表明clang不会忽略提示,这使得当前答案是错误的,因为现在至少clang仍然在寻找inline关键字并做出一些决策。 - Victor Polevoy
是的。具有讽刺意味的是,2009年11月给出的答案与2014年11月给出的答案相比更为现代化。当我提出问题时,我希望前者是正确的,并且那正是我的假设。很可能,2014年11月给出的答案可能是Clang限制的孤立情况。无论如何,我将标记此问题以列出可能的重复,并请求重新打开 - iammilind
1
有些编译器可以让你选择。例如,MSVC有以下选项:不内联任何东西、仅内联标记为“inline”的函数或者无论是否标记为“inline”,都内联显然应该内联的任何内容。 - Bo Persson
2
你误解了你链接的答案,或者没有完全阅读它。该答案并没有说inline只是一个被忽略的提示,它说inline改变了语言语义,使得函数可以在多个翻译单元中定义。这不仅仅是为了向后兼容,而且是C++语言和链接模型的重要属性。因此,你的整个问题似乎基于错误的前提。inline不是“只是一个提示”,它改变了代码编译和链接的方式,以便编译器可以进行内联(无需LTO)。 - Jonathan Wakely
@jonathan namespace{}也可以实现这一点而无需使用LTO,并且不太可能引起ODR违规。(但是,如果您要内联非LTO函数中的static局部变量,则仍然需要它!) - Yakk - Adam Nevraumont
显示剩余5条评论
3个回答

7
  1. 不是,它们只是按照标准要求进行解释,但一些编译器可能仅限于此(据文档所述,MSVC会基于inline关键字的存在进行选择,GCC 5.1.0在决定时也会考虑inline关键字)。
  2. 不是,为了避免链接时出现重复符号,需要使用inline关键字。

inline关键字确实有意义,但并非您可能期望的意义。它并不意味着编译器必须/应该/可以将函数内联展开,编译器可以根据自己的判断决定是否这样做,而不管您是否使用inline关键字。

它的意思是,您应该并且可以在每个编译单元中重复函数定义,而不会导致链接错误-这与static关键字非常相似。

例如,GCC 4.7.2(可能不是最先进的编译器,但仍然是相当现代的编译器)似乎不比标准规定更多地解释inline。如果禁用优化,则不会内联函数;如果启用优化,则似乎会按照自己的意愿内联。唯一的区别在于编译器如何处理不同情况下的“轮廓”函数,在使用inline时,它会简单地丢弃它或以避免链接时出现重复符号的方式处理它。


2
我认为维克多理解inline是一个提示,他想知道现代编译器是否仍将其视为提示,还是通常会忽略它。 - TartanLlama
2
这已经在问题中发布的链接的选定答案中解释过了。 - juanchopanza
1
@VictorPolevoy 我不知道你希望得到什么样的答案。有些编译器不会根据 inline 关键字选择内联,而有些编译器可能会根据此进行选择。 - skyking
1
@Yakk 是的,那很糟糕,但我目前不知道如何提及它才能适合答案。 - skyking
@skyking 谢谢你的解释,我已经点赞了你的回答。似乎我对 inline 的某些部分理解不够。 - Victor Polevoy
显示剩余7条评论

3
现代的C++11兼容编译器是否总是忽略用户指定的内联提示,而只在自动情况下执行?
C++11与此无关,C++11标准并没有改变inline的语义,编译器优化与被编译的语言版本基本独立。
内联提示仅保留以提供向后兼容性吗?
不,inline不是提示,编译器也不会“忽略”inline,因为如果这样做,您将得到多个定义错误。编译器赋予inline关键字的含义与您所理解的含义不同。它不是提示。
如果编译器看不到函数定义,它就无法将其内联(链接时优化改变了这一点,但使用LTO并不是很普遍,大多数库不会提供启用了LTO的二进制文件,这将允许链接时内联)。
您应该将inline读作“此函数定义出现在此文件中”,而不是“调用此函数应内联”。
因此,inline关键字对于使编译器能够查看多个文件中的函数定义非常有用,这意味着它有可能通过内联调用来优化它们。这并不一定比在同一翻译单元中定义的任何其他函数更容易内联。
对于从多个翻译单元调用的函数,在头文件中定义它们并使它们inline是编译器内联它们的必要条件,但这并不足够(因为编译器基于其他条件进行内联决策)。
这与向后兼容性无关,今天与2009年一样正确。

1
@Yakk,为什么匿名命名空间是C++11的替代方案?它们在C++03中也存在。我没有提到使用它们或static,因为它们是不同的解决方案,具有不同的结果,并不是inline函数的即插即用替代品。它们解决了不同的问题(如果它们没有被内联,由于链接器需要保留所有定义,可能会导致显著的代码大小增加)。 - Jonathan Wakely
@VictorPolevoy,答案不清楚吗?如果您想在头文件中定义函数而不出现多重定义错误,应该使用inline关键字。这正是旧答案所说的。您不理解哪一部分?显然它不是无用的,因为如果您从头文件中删除inline,代码将无法链接。 - Jonathan Wakely
认真吗?在头文件中定义一个函数,不使用inline关键字。将头文件包含在两个不同的文件中。将这些文件链接在一起。 - Jonathan Wakely
什么被广泛使用?头文件?函数?是的。 - Jonathan Wakely
@JonathanWakely 谢谢你花时间和我交流。现在我感到非常惭愧。可能是我读多了一些言外之意。 - Victor Polevoy
显示剩余2条评论

2
C++11编译器与C++03或其他版本一样,遵循内联提示。
但是,请注意,关键字inline不是内联提示。提示看起来更像__attribute__((always_inline))inline关键字(或应用于模板等的隐式内联状态)表示函数在头文件中定义,因此链接器在合并翻译单元(.cpp文件)时应该期望看到多个副本。它被命名为这个原因是定义必须可用才能内联一个函数,这意味着库中的函数需要inline才能实现内联。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接