有没有一种方法可以分隔“ inline”关键字的两种含义(ODR松弛与函数代码内联)

时间:2018-12-16 17:03:41

标签: c++

我想我完全理解C ++中inline关键字的含义。具体来说,它仅意味着两件事:

  1. 对于声明为inline的函数,ODR规则已放松。因此,您可以在多个TU中定义相同的功能符号,而在链接它们时不会出错。这样就可以在标头中定义函数。
  2. 对编译器的建议是 ,它应使用函数已编译代码的副本代替函数调用,而不要使用指向函数符号地址的call指令。

我可以理解,这两个含义必然在一个方向上相关:2必须隐含1。#2要求函数定义对于调用该函数的所有TU都可用。因此,功能定义必须存在于多个TU中。因此,需要放宽ODR以避免链接器错误。

但是我的问题是另一个方向-为什么将语言设计为1必须隐含2?

在某些情况下和某些设计决策中,希望能够放宽函数的ODR似乎是合理的,而没有则建议编译器实际上应该内联函数代码。如果我有要通过头文件分发的函数,则必须将其标记为inline以放宽ODR(#1)。但是,即使我对性能有特定的了解,但现在我还是被迫进入第二名。该功能不是内联的理想选择。

我的理解是模板功能不存在这种不必要的含义。将自动放松ODR以使用模板功能(必须如此)。这使我只能将inline用作性能建议。

我知道在标头文件中分配函数,而不是像静态库,可能不是一个好主意。但是作为一名程序员,我有可能知道自己在做什么,并且我希望这种灵活性。我具有模板功能的灵活性,那么为什么不使用非模板功能呢?

或者是否存在一种便携式的方式来放松ODR而又不建议内联该功能?例如。在MSVC上,您可以执行以下操作:

__declspec(noinline) inline void Foo() {}

此处inline放宽了ODR,但是__declspec(noinline)请求编译器 not 实际上内联该调用。但是__declspec(noinline)不可移植。

谢谢!

1 个答案:

答案 0 :(得分:5)

  

为什么设计该语言时必须将1隐含为2?

语言不是这样设计的。

该语言根本无法明确指定应该或不应该内联扩展的函数-既不是强制性的也不是优选的。

语言都没有指定内联声明暗含对内联扩展的偏好。尽管如此,编译器实现者发现让程序员表达他们对内联扩展的偏好很有用。大概是由于缺乏标准的方式来明确表达该偏好,因此编译器实现者选择让内联声明暗示该偏好。

由于该语言缺乏表达内联扩展偏好的标准方法,因此只能使用特定于实现的语言扩展来表达。

  

但是__declspec(noinline)不可移植。

您可以使用平台检测宏将其移植到具有类似属性的所有实现中。 GCC和Clang有__attribute__((noinline))


另一种方法是根本不在乎。编译器仍然可以选择忽略它认为隐含的首选项。如果内联扩展会很昂贵(因为功能很大),那么聪明的编译器应避免扩展它。