用于头文件中的匿名命名空间
Posted
技术标签:
【中文标题】用于头文件中的匿名命名空间【英文标题】:Uses for anonymous namespaces in header files 【发布时间】:2010-09-26 07:59:44 【问题描述】:今天有人在 SO 上断言,你永远不应该在头文件中使用匿名命名空间。通常这是正确的,但我似乎记得曾经有人告诉我,其中一个标准库在头文件中使用匿名命名空间来执行某种初始化。
我没记错吗?有人可以填写详细信息吗?
【问题讨论】:
查看此讨论:http://***.com/questions/357404/anonynous-namespaces 这是他从标头中的匿名命名空间获取信息的线程是错误的 我在该线程中找不到任何关于在头文件中使用它的信息。谁能解释为什么这是错误的?它仍然适用于 C++11 吗? 【参考方案1】:在标头中使用无名命名空间的唯一情况是您只想将代码作为标头文件分发。例如,Boost 的一个大型独立子集纯粹是标头。
另一个答案中提到的元组标记ignore
是一个例子,_1
、_2
等绑定占位符是其他的。
【讨论】:
您不应该为此使用匿名命名空间,因为它们在最终编译单元中都折叠在一起,可能导致命名空间冲突。取而代之的是,使用一个按照惯例意味着内容是实现细节的名称。例如,Boost 使用detail
。
@thehouse 您似乎误解了 Boost 如何使用匿名命名空间。 ignore
和 _1
、_2
等是公共符号 - 它们不属于 detail
。但我同意详细命名空间通常是头库等效于匿名命名空间的正确选择。
@JamesHopkin 总是乐于学习。你能解释一下为什么 _1 和 _2 在匿名命名空间中,而不仅仅是在namespace boost
中吗?这有什么优势?
@thehouse 允许仅标头库提供全局对象是一种技巧,这通常会导致链接错误。将对象放入匿名命名空间会强制每个编译单元创建自己的实例。对于 _1、_2 等,多个实例无关紧要,因为它们是无状态的。实现相同效果的另一种方法是使用模板类的静态成员,但是客户端必须键入类似 Dummy::_1 而不仅仅是 _1。
最先进的方法来定义_1
、_2
、ignore
等是使用inline
变量。【参考方案2】:
我认为将匿名命名空间放入头文件中没有任何意义。我已经找到了标准和 libstdc++ 标头,在 tuple
标头(C++1x 的东西)中除了一个之外没有发现匿名名称空间:
// A class (and instance) which can be used in 'tie' when an element
// of a tuple is not required
struct _Swallow_assign
template<class _Tp>
_Swallow_assign&
operator=(const _Tp&)
return *this;
;
// TODO: Put this in some kind of shared file.
namespace
_Swallow_assign ignore;
; // anonymous namespace
这样你就可以了
std::tie(a, std::ignore, b) = some_tuple;
some_tuple 的元素被分配在左侧的变量(参见here),类似的技术用于this 迭代器。第二个元素被忽略。
但正如他们所说,它应该被放入一个 .cpp 文件中,并且一个实例应该由所有用户共享。然后他们会将它的声明放入标题中:
extern _Swallow_assign ignore;
【讨论】:
C++1x?我错过了什么吗? Sutter 仍将其称为 C++0x (herbsutter.wordpress.com/2008/10/28/…)。 等等.. 现在我明白他为什么称我为悲观主义者了 :) 好吧 litb 和其他一些悲观主义者称它为 c++1x。让我们看看谁会赢得赌注:p【参考方案3】:我已经看到它用于为不同翻译单元中的变量提供默认值。但在名称冲突的情况下可能会导致意外行为。
例子
a.hpp
namespace
const char name[] = "default";
// This macro will hide the anonymous variable "name"
#define SET_NAME(newname) \
static const char name[] = newname;
b.cpp
#include "a.hpp"
SET_NAME("file b") // name is "file b" in this translation unit
c.cpp
#include "a.hpp"
SET_NAME("file c") // name is "file c" in this translation unit
d.cpp
#include "a.hpp"
// name is "default" in this translation unit
e.cpp
#include "a.hpp"
static const char name[] = "unintended";
// accidently hiding anonymous name
【讨论】:
【参考方案4】:我真的看不出在标头中使用匿名命名空间没有任何积极的好处。具有相同符号声明可能导致的混乱意味着,本质上,包含该标头的编译单元中的不同事物将保证过早地和痛苦地秃顶。
【讨论】:
【参考方案5】:如果是初始化,它可能是iostream
s 标头(如istream
、ios
等)。
【讨论】:
以上是关于用于头文件中的匿名命名空间的主要内容,如果未能解决你的问题,请参考以下文章
C++函数通过头文件分享给其他源文件时,使用命名空间方式,和使用类中静态函数方式,有何区别?