跨多个 C++ 翻译单元的内联函数

Inline functions across multiple C++ translation units

我最近了解了 C++ 中的内联函数。我了解它们的工作原理(在扩展代码而不是跳转等方面),但是我对在涉及多个翻译单元/*.cpp 文件时应该如何使用它们感到有点困惑。

我读过,根据经验,我应该在头文件中包含函数本身的定义(而不仅仅是它的声明),然后在我打算翻译的每个翻译单元中包含头文件使用所述内联函数。这对于内联函数来说不是问题,因为它只会在每个翻译中独立存在并扩展自身 when/if 需要(由编译器决定)[如果我对此有任何错误,请纠正我!]

不过,我也看到在link期间,即使内联函数本身的定义不存在于头文件中,linker也可以找到它的定义并展开它如果需要的话。但是 linker 如何能够从不同的翻译单元扩展功能?如果是这样,为什么我需要在每个翻译单元中包含函数的定义(通过头文件)?

函数前面的 inline 关键字只是编译器的一个可选指示器,指示内联是首选。当涉及代码内联时,现代编译器不关心 inline 关键字。

关于inline的重要意义是“允许多个定义”,如果成员函数定义在class的body中,则隐式内联。

如果您在多个翻译单元中具有相同的函数定义,则需要 inline(例如,如果您将函数定义放在 header 中,并且 header 包含在多个翻译单元中cpp 文件)

I've read that, as a rule of thumb, I should contain the definition of the function itself inside a header file (and not just its declaration) and then include the header file in each translation unit I aim to use said inline function. That is not a problem for an inline function, since it will just exist standalone on each translation and expand itself when/if needed (decided by the compiler)

在header中放置一个函数定义使得工具链更容易进行内联,因为它在使用时知道它的定义并且可以在编译步骤中执行内联。在多个翻译单元中定义函数需要用 inline.

标记

However, I also read that during link time, even if the definition of an inline function itself is not present in the header file, the linker can find its definition and expand it if needed. But how would the linker be able to expand a function from a different translation unit?

工具链可以对在 linking 时已知定义的任何函数(无论它们的定义是否在编译时已知)进行 link-time 优化(如内联)(静态linking),但 link-time 优化往往 - 至少在过去 - 不如 compile-time 优化有效。

link-time 优化的问题是,工具链要么需要跟踪源代码提供的有助于优化的附加信息,要么需要依赖可能不太强大的策略在二进制文件上。

如果您的 main.cpp 看起来像这样:

int sum(int a, int b) {
  return a+b;
}

int main() {
  std::cout << sum(3,4) << std::endl;
  return 0;
}

任何现代编译器都会内联该代码(或者在那种情况下将其完全优化为 std::cout << 7 << std::endl;)。

这样也行 inlined/optimized:

sum.h

int sum(int a, int b) { // no inline keyword in front of the function
  return a+b;
}

main.cpp

#include "sum.h"
int main() {
  std::cout << sum(3,4) << std::endl;
  return 0;
}

但是一旦你在多个 cpp 文件中使用 #include "sum.h" 并且 link 这些翻译单元一起使用,你就会遇到问题并且需要使用 inlineinline 在函数前面实际上只是告诉 linker 在多个翻译单元中具有相同的定义是你的意图。