【问题标题】:Could I provide same function definition in different TUs我可以在不同的 TU 中提供相同的函数定义吗
【发布时间】:2019-10-26 04:12:05
【问题描述】:

我正在阅读有关内部和外部链接的信息,我发现默认情况下,函数具有外部链接。

所以我在想是否可以在头文件管理器中声明一个函数并在不同的翻译单元中提供它的多个定义。

到目前为止,我确实在头文件中声明了一个函数

void fct();

并在两个文件中提供 2 个定义,每个文件都包含在一个匿名命名空间中:

namespace
{
    void fct()
    {    
    }    
}

但我不明白这怎么能成为在不同 TU 中使用函数的多个定义的好例子。

谁能给我看一个简单的例子(即使使用内联) 谢谢

【问题讨论】:

  • 匿名命名空间中的定义与头文件中的声明不匹配。你到底想达到什么目标?
  • 我想要实现的是在两个不同的翻译单元中编写一个函数的 2 个定义(甚至相同)。我读到内联函数是一个可能有多个定义的函数(但它们必须相同)。
  • @Blood-HaZaRd - 这仅适用于内联函数。您可能没有多个非内联函数的定义。如果成功,您将收到链接器错误。如果您没有收到链接器错误,则说明您没有成功。
  • 您最好稍微扩展一下 Pimpl idiom 来实现这一点。
  • @Blood-HaZaRd - 匿名命名空间可以被认为是一个命名空间,其名称对于每个翻译单元都是唯一的。函数的名称包括声明它的命名空间。因此,每个位于匿名命名空间但位于不同翻译单元中的两个函数具有不同的名称,即使声明中的函数名称看起来相同。

标签: c++ linkage one-definition-rule translation-unit


【解决方案1】:

能否在不同的 TU 中提供相同的函数定义

如果函数没有内联声明,则否;这将违反单一定义规则。

可以在多个 TU 中定义具有外部链接的内联函数 - 附加要求定义必须相同。事实上,内联声明将强制要求在所有使用该函数的 TU 中提供定义。

并在两个文件中提供 2 个定义,每个文件都包含在一个匿名命名空间中:

这并不违反标准规则。这两个函数不一样,也和全局的::fct不一样。

但我不明白这怎么能成为在不同 TU 中使用函数的多个定义的好例子。

谁能给我看一个简单的例子(即使使用内联)谢谢

给你:

// header.hpp
inline void foo() {}

// a.cpp
#include "header.hpp"

// b.cpp
#include "header.hpp"

这里有两个 TU,每个都包含函数 ::foo 的定义,包含在同一个标​​头中。这是允许的,因为该函数是内联声明的。


相关标准引用(当前草案,不相关的细节由我编辑):

单定义规则[basic.def.odr]

A ...函数,...不应在先前定义必须可达的情况下定义([module.reach]);如果先前声明在另一个翻译单元中,则不需要诊断。

...

每个程序都应包含一个定义,即在该程序中被丢弃的语句之外的每个非内联函数或变量的定义;无需诊断。 ... 内联函数或变量的定义应可在每个翻译单元中访问,在该翻译单元中,在废弃语句之外使用它。

...

在程序中可以有多个定义 ... 具有外部链接 ([dcl.inline]) ... 的内联函数 ... 前提是在定义出现的点,并且定义满足以下要求。 ... 不需要诊断,除非在稍后的定义出现时可以达到先前的定义。 给定这样一个名为 D 的实体在多个翻译单元中定义,那么

  • D 的每个定义都应由相同的标记序列组成;和
  • ~其他限制的长列表~

【讨论】:

  • 单一定义规则也适用于内联函数。 ODR 实际上与此无关。这里的规则是,可能只有一个具有外部链接的名称定义不是内联函数。这就是为什么 C++17(或者是 2a?)使用 inline 关键字的原因,以便您可以在头文件中初始化静态变量(会出现在多个 TU 中)。
  • @eerorika 添加一个解决方案,如何通过 Pimpl 的变体克服这个问题,我会投票赞成(你已经正确的)答案。
  • @πάνταῥεῖ:如果我能看到 Pimpl 的一个例子,那就太好了,因为我不知道我们如何使用指向另一个类的指针来做 thar !?!对不起,如果我的谈话看起来很愚蠢,但我可能不像这里的其他人那么聪明:)
  • @Blood-HaZaRd 这意味着首先要引入类来调用这些函数。
  • @MartinBonner 是的,我的意思是,目前还不清楚它解决了这个问题(和答案)的上下文中的什么问题:) 那就是:我没有看到问题中提到的可以解决的问题使用 Pimpl。
猜你喜欢
  • 1970-01-01
  • 2020-06-08
  • 1970-01-01
  • 2020-12-23
  • 2021-07-17
  • 2016-03-02
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
相关资源
最近更新 更多