首页 > 解决方案 > 有没有办法将“内联”关键字的两个含义分开(ODR 放松与功能代码内联)

问题描述

我想我完全理解inlineC++ 中关键字的含义。具体来说,它意味着两个半相关的事情:

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

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

但我的问题是关于另一个方向 - 为什么语言设计成 1 必须暗示 2?

在某些情况下和某些设计决策中,希望能够放宽函数的 ODR,而不建议编译器实际上应该内联函数代码,这似乎是合理的。如果我有一个想要通过头文件分发的函数,我必须将其标记为inline放宽 ODR (#1)。但是现在我被迫进入#2,即使我有具体的知识,就性能而言,该函数不是内联的好候选者。

我的理解是,模板函数不存在这种不需要的含义。模板函数的 ODR 会自动放宽(必须如此)。这使我inline只能将其用作性能建议。

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

或者是否有一种可移植的方式来放松 ODR 而不建议内联函数?例如,在 MSVC 上,您可以这样做:

__declspec(noinline) inline void Foo() {}

这里inline放宽了 ODR,但__declspec(noinline)要求编译器实际上内联调用。但是__declspec(noinline)不便携。

谢谢!

标签: c++

解决方案


但是__declspec(noinline)不便携。

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


另一种方法是根本不在乎。编译器仍然可以选择忽略它认为已经隐含的偏好。如果内联扩展很昂贵(因为函数很大),智能编译器应该避免扩展它。


推荐阅读