【问题标题】:When is an empty namespace definition needed?什么时候需要一个空的命名空间定义?
【发布时间】:2011-04-17 23:53:02
【问题描述】:

命名空间不像大多数其他事物那样被声明和定义,但命名空间等价于前向声明将是:

namespace X {}  // empty body

通常,您通过在其中放置其他声明来定义命名空间。但是这个“命名空间前向声明”是最简单的解决方案吗?空的命名空间有什么用?

【问题讨论】:

  • 我有一个特定的情况,我发现这很有用。如果在接下来的一两天内没有人回答,我会发布它。我很好奇是否还有其他情况。
  • 有趣的问题。 +1我想不出这会是有利的情况(尽管您可能会想出一个病态的例子)。我很好奇……

标签: c++ namespaces forward-declaration


【解决方案1】:

这甚至出现在标准中:声明一个 using 指令来表示一个命名空间

namespace unique { }
using namespace unique;

之后,您可以在其他时间打开命名空间并添加到其中,而 using 指令使这些内容对外部命名空间可见。

【讨论】:

  • 标准中的哪个地方?
  • @Roger 7.3.1.1/1,未命名的命名空间
  • 啊,我已经掩饰了很多次了,我应该认出来的。我看不到第二个中的空命名空间声明在哪里——如果是 lambda,你要定义什么成员?
  • @Roger 类似flm::_1 之类的。 :) 但我不确定这个用途,所以我要再次删除它。因为将命名空间别名放在标题中是很糟糕的,而且我只在 .cpp 文件中看到这种东西的有限用途(如果你在 foo::lambda 内,目前你可以只使用不合格的名称)。
  • 我的使用类似于 WRT 使用指令,但用于不同的目的(并且旨在在有限的范围内使用,与上述不同)。我认为这可能有用的唯一方法是使用指令;在没有其他上下文的情况下,您实际上可以使用命名空间。或者,如果添加到库的名称空间没有(程序上而不是正式地)受到限制,它是否可以用于“保留”名称? (这似乎不是一个好主意。)
【解决方案2】:

我使用空的命名空间定义来简化递归函数的声明,其中一个“方面”是运算符重载。运算符被放置在自己的命名空间中,以便根据需要在范围内进行选择性使用,而不是在标头包含在任何地方时强制使用(因此如果分辨率变得不明确则强制错误)。

Example:

namespace container_inserters {}

template<class Stream, class Iter, class Ch>
void write_sequence(Stream& s, Iter begin, Iter end,
                    Ch const *initial, Ch const *sep, Ch const *final)
{
  using namespace container_inserters;
  if (initial) s << initial;
  if (begin != end) {
    s << *begin;
    ++begin;
    for (; begin != end; ++begin) {
      if (sep) s << sep;
      s << *begin;
    }
  }
  if (final) s << final;
}

namespace container_inserters {
#define G(N) \
template<class Ch, class Tr, class T, class A> \
std::basic_ostream<Ch,Tr>& operator<<(std::basic_ostream<Ch,Tr> &s, \
                                      N<T,A> const &value) \
{ \
  write_sequence(s, value.begin(), value.end(), "[", ", ", "]"); \
  return s; \
}
G(std::deque)
G(std::list)
G(std::vector)
#undef G
}  // container_inserters::

s &lt;&lt; *begin 的解析延迟到 write_sequence 被实例化(因为它涉及模板参数),此时操作符已经被声明并且可以通过 using 指令找到。对于嵌套容器,调用变为递归:

int main() {
  using namespace std;
  vector<deque<list<int> > > v (3, deque<list<int> >(2, list<int>(1, 42)));

  using namespace container_inserters;
  cout << v << '\n';

  return 0;
}
// output:
//  [[[42], [42]], [[42], [42]], [[42], [42]]]

Boost 有类似的输出格式库,但我不知道他们是否使用相同的实现技术。

【讨论】:

    猜你喜欢
    • 2015-09-15
    • 2013-10-16
    • 2014-10-18
    • 1970-01-01
    • 1970-01-01
    • 2015-09-07
    • 2016-12-10
    • 2015-02-10
    • 1970-01-01
    相关资源
    最近更新 更多