解决多定义问题的内联函数是 well-defined 吗?

Is inlining function to solve multi definition a well-defined thing?

我正在构建一个 templated-header-only C++11 库。正如我所读到的,我应该将我的成员函数定义为inline,以保证在翻译单元中不会出现定义的多重存在。

这是 well-defined 对 inline 关键字的使用吗?我曾经认为 inline 是 performance-related 的东西。我怀疑为此目的使用 inline 就像打开后门一样。使用它有什么缺点吗?还有其他解决方案吗?

如果您阅读例如this inline reference 你会看到带有外部链接的函数的属性列表,第二点说:

It has the same address in every translation unit.

这意味着将函数声明为 inline 将导致该函数在所有 translation units 中仅存在一个实例(即从源文件生成的所有目标文件)。

由于该函数只有一个实例,因此不会出现任何多重定义错误。

Joachim 的问题回答了有关内联语义的主要问题,但 OP 还询问了使用内联的缺点。执行内联时通常的 trade-off 介于代码大小和速度之间。我们有两种情况:

  1. 函数实际上是内联的。在这种情况下,主体被复制到各处,增加了最终程序的代码大小。这可能还包括性能损失,因为在处理器缓存中缓存程序代码变得更加困难。

  2. 该函数未内联。我假设一个带有外部链接的内联函数。在这种情况下,链接器将删除除一个以外的所有副本,以确保该函数的地址在整个程序中是唯一的。此过程会减慢您的构建过程。在 msvc <= 2010 上,这曾经是一个主要问题,因为链接器是单线程的并且非常慢。

  3. 内联函数必须在它们使用的每个编译单元中进行解析和编译。这会减慢构建过程。

更好的方法可能是使用 whole-program 优化,其中编译器可以跨编译单元进行优化。所有主要的编译器都支持这个。

就标准而言,inline关键字的意义在于防止多重定义错误

一旦您在多个翻译单元中定义了函数,编译器可能在每个翻译单元中包含该函数的副本(尽管他们必须确保获取函数给出一个唯一的结果),他们可能决定在每个调用点扩展该函数(或者他们可能不会)。

如果您想要一个 header-only 库,将成员标记为 inline(使用关键字,或者通过在 class 的 body 中定义它们)是强制性的。 header only 库的优点是易于使用,缺点是编译客户端可能需要更长的时间,更改时可能需要重新编译更多内容。