何时需要使用空命名空间定义?

3

命名空间不像大多数其他东西那样声明和定义,但前向声明的命名空间等效物将是:

namespace X {}  // empty body

通常,您可以通过在命名空间中放置其他声明来定义命名空间。但是是否存在这样的问题,需要使用“命名空间前向声明”作为最简单的解决方案?空命名空间有什么用处?


我有一个特定的情况,发现这很有用。如果未来一两天没有人回答,我会发布它。我非常好奇是否还有其他情况。 - Roger Pate
有趣的问题。+1 我想不出这种情况会有什么优势(虽然你可能可以构造一个病态的例子)。我非常好奇... - JoshD
相关: https://dev59.com/XVDTa4cB1Zd3GeqPIVqc - James McNellis
2个回答

4

以下是一种在标准中出现的方法:使用using指令来表示一个命名空间。

namespace unique { }
using namespace unique;

之后,您可以多次打开命名空间并向其中添加内容,而using指令可以使该内容对外部命名空间可见。


那在标准中的哪里? - Roger Pate
@Roger 7.3.1.1/1,未命名的命名空间 - Johannes Schaub - litb
啊,我已经在那上面匆忙看过太多次了,我应该能够认出来的。我不知道第二个里面空命名空间声明在哪里——如果是Lambda,你将定义哪些成员? - Roger Pate
@Roger 类似于 flm::_1 或类似的东西。:) 但我不确定这种用法,所以我打算再次将其删除。因为在头文件中放置该命名空间别名是很糟糕的,而且我只看到在 .cpp 文件中有限制使用这样的东西(如果您当前在 foo::lambda 中,则仍然可以使用未限定名称)。 - Johannes Schaub - litb
我的用法类似于使用指令,但目的不同(并且旨在在有限范围内使用,与上述不同)。我认为这只有在使用指令时才有用;在没有其他上下文的情况下,您实际上无法使用命名空间。或者,它可以用于“保留”名称,如果添加到库的命名空间不受(程序而非正式)限制怎么办? (那似乎不是一个好主意。) - Roger Pate

2

我使用空命名空间定义来简化递归函数的声明,其中一个“方向”是运算符重载。运算符被放置在它们自己的命名空间中,以允许选择性地在所需的作用域中使用,而不是强制使用头文件在任何地方都被包含(从而在解析变得模糊时强制出现错误)。

示例

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 << *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拥有一个类似的输出格式库,但我不知道它们是否使用相同的实现技术。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接