内联函数和一个定义规则

时间:2017-05-15 01:07:40

标签: c++ c++11 inline one-definition-rule

inline函数提供了一个定义规则的弱化 - 允许多个定义,尽管有一些限制。我在网上找到的一个措辞是

  

要求是每个定义应该相同,这意味着它应该包含相同的标记并引用相同的项目。

虽然我承认我不知道这是否是最终的。我也不确定它有多严格。

我正在考虑使用class定义和/或inline函数创建标题的情况我想成为#include - 是否可以在C +中编译+ 03,C ++ 11,甚至更晚的标准。使用__cplusplus宏来有条件地更改代码是很自然的,但是ODR会发挥作用吗?例如,有条件地

似乎是合理的
  • 提供嵌套的typedef
  • 提供嵌套的class
  • 提供与移动相关的功能。
  • 标记函数throw()noexcept。 (这一点尤为重要,因为每个析构函数都会在C ++ 11中选择隐式noexcept。)
  • 标记函数constexpr
  • 使用override和/或final标记功能。
  • 标记函数[[noreturn]]和/或[[nodiscard]]
  • 标记参数[[maybe_unused]]
  • 在函数体中使用[[fallthrough]]

但如果想要启用#include这些标题库以不同标准编译并且仍然可以安全使用的库,那么实际上允许哪些 - 如果有的话 -

1 个答案:

答案 0 :(得分:0)

一般情况下,你不能安全地做任何这些事情。安全使用说两种类的定义只有两种方法。通过简单的方式,您可以简单地编译两个单独的进程,这些进程通过例​​如共享内存。更简单的是,如果出现以下情况,您可以使用两个以两种不同方式定义相同符号A的库:

  • 符号A只是库的实现细节;它不能由库提供也不能出现在任何接口中
  • 沿着这些方向,库的头文件都不应该传递包含A的头。因此,客户端翻译单元不会从库中收到任何A的定义。
  • 符号A的可见性必须标记为私有/隐藏。

如果你做了所有这些,那么A确实是库的实现细节,你可以使用多个以不同方式定义A的库。如果其中任何一个不满意,那么你不能保证上述任何一个都可以工作(虽然有些人会这样做)。

对于不熟悉链接器的人来说,最令人惊讶的结果之一是,如果lib1和lib2都使用符号A,即使它们阻止任何通过头部的泄漏,如果A的可见性是公开的,那么单个定义将在两个库中使用A.因此lib2将使用lib1的定义,反之亦然。这很容易导致UB。

在* nix系统上,公共可见性是默认设置,因此您需要确保隐藏符号,这有点神秘。