当 header 和实现分开时,静态或未命名的命名空间是否仍然有用?

Are static or unnamed namespace still useful when header and implementation are separated?

正如此 question 中的回答,我了解到该函数的 static 关键字意味着它只能从该文件中的函数中看到。我认为未命名的命名空间可以用于相同的目的。

但是,通常,实现文件和 header 文件是分开的。因此,在我看来,程序员可以通过不在 header 文件中编写此类私有内容的声明来隐藏实现文件中的所有“私有内容”。

考虑到以上内容,static 和未命名命名空间何时有用?我能想到的唯一情况是多个实现文件对应一个 header 文件。

在实现文件中保留定义在任何意义上都不会使其成为私有的。任何其他 header 或实现文件都可以声明该函数并使用它。这并不总是一件坏事——当我真正需要它时,我使用了库的部分私有实现(但我不建议这样做)。

这种 not-so-private 实施的最糟糕的部分是它可能违反单一定义规则。 ODR 声明每个*函数或变量在整个程序中必须只有一个定义。如果有多个定义,则行为未定义**。
这意味着当您的文件中有 not-so-private 实现但没有人知道时,他们可能会在不知不觉中编写具有相同名称和参数的函数并导致 ODR 违规。

最好对所有应限制在单个文件中的自由函数使用 static 或匿名命名空间。需要从其他文件使用的函数不能使用此策略,因此要限制违反 ODR 的风险,您应该使用描述性名称,或许还可以使用(命名的)名称空间。只要确保 you don't overuse namespaces.


注意:在 header 文件中使用匿名名称空间没有意义。匿名命名空间将其内容的范围限制在它所在的翻译单元中,但是 header 文件被复制并粘贴到(可能)多个 TU 中。匿名命名空间的一种用途是在 header-only 库中,如 this question 中所述 - 它允许在 header 文件中创建全局 objects 而不会违反 ODR(但代价是每个 TU 都有自己的该变量副本)。


* 除了模板函数、inline 函数、class 定义中定义的函数以及更多。即使这样,所有的定义也必须完全相同。

**当我遇到一次时,链接器使用随机定义,以当时看到的为准。随之而来的是欢闹和长时间的调试。