【问题标题】:Uses for anonymous namespaces in header files用于头文件中的匿名命名空间
【发布时间】:2010-09-26 07:59:44
【问题描述】:

今天有人在 SO 上断言,你永远不应该在头文件中使用匿名命名空间。通常这是正确的,但我似乎记得曾经有人告诉我,其中一个标准库在头文件中使用匿名命名空间来执行某种初始化。

我没记错吗?有人可以填写详细信息吗?

【问题讨论】:

标签: c++ namespaces initialization header


【解决方案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_2ignore等是使用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】:

      如果是初始化,它可能是iostreams 标头(如istreamios 等)。

      【讨论】:

        猜你喜欢
        • 2016-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-10
        • 2013-09-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多