为什么我们不能在类中声明命名空间?

时间:2012-11-21 00:10:57

标签: c++ class namespaces

在类中声明一个类是有效的。 (嵌套类)

在类中声明命名空间无效。

问题是:是否有任何理由(除了c ++语法/语法问题)禁止在类中声明命名空间?


至于我为什么要这样做,这是一个例子:

让我们对二叉树容器进行基本的移植

template<typename Data>
class binary_tree
{
 public:
  ... stuff ....     

 private:
  ... iterators class declaration ...

 public:
  typedef left_depth_iterator_impl     left_depth_iterator;
  typedef right_depth_iterator_impl    right_depth_iterator;
  typedef left_breadth_iterator_impl   left_breadth_iterator;
  typedef right_breadth_iterator_impl  right_breadth_iterator;

  ... stuff ....     

 private:
  Data         data;
  binary_tree* left;
  binary_tree* right;
};

现在我注意到我的类中有很多迭代器,所以我想将它们重新组合在同一个命名空间中,如下所示:

template<typename Data>
class binary_tree
{
 public:
  ... stuff ....     

 private:
  ... iterators class declaration ...

 public:
  namespace iterator
  {
    typedef left_depth_iterator_impl     left_depth;
    typedef right_depth_iterator_impl    right_depth;
    typedef left_breadth_iterator_impl   left_breadth;
    typedef right_breadth_iterator_impl  right_breadth;
  }

  ... stuff ....     

 private:
  Data         data;
  binary_tree* left;
  binary_tree* right;
};

这样可以简单使用:

void  function()
{
  binary_tree::iterator::left_depth   it;

  ...stuff...
}

如果我使用类而不是命名空间,这是有效的,但是我被迫声明一个永远不会被实例化的类,这是一个非常命名空间。

为什么允许嵌套类并禁止类中的嵌套命名空间?这是传统的负担吗?


具有语义原因的答案不仅引用了标准的一部分(特别是语法部分),而且会引起误解:)

5 个答案:

答案 0 :(得分:43)

由于您询问了标准命名空间位置的哪些部分,我们先点击它:

  

C ++ 11 7.3-p4:每个命名空间定义都应出现在全局范围或命名空间范围内(3.3.6)。

关于类定义和在其中声明命名空间的提议,我带你去...

  

C ++ 11 9.2-p2:在类说明符的结束时,类被视为完全定义的对象类型(3.9)(或完整类型)。在类成员规范中,对于非静态数据成员(包括嵌套类中的此类事物),该类在函数体,缺省参数,异常规范和大括号或大小写初始化中被视为完整。否则,它在其自己的类成员规范中被视为不完整。

Ergo,一旦达到收尾卷曲,类定义就是有限的。它无法打开和扩展(派生是不同的,但它不是扩展刚刚定义的类)。

但潜伏在命名空间的标准定义的最开始是扩展它的能力;因缺乏更好的术语而扩大它:

  

C ++ 7.3-p1:命名空间是一个可选命名的声明性区域。命名空间的名称可用于访问在该命名空间中声明的实体;也就是命名空间的成员。 与其他声明性区域不同,命名空间的定义可以分为一个或多个翻译单元的几个部分。(强调添加)。

因此,类中的命名空间将违反7.3-p4中的定义。假设不存在,那么可能在任何地方声明一个命名空间,包括在一个类中,但是由于一个类的定义一旦被关闭就形式化了,你将只剩下这个能力如果您遵守7.3-p1:

,请执行以下操作
class Foo
{
   namespace bar
   {
       ..stuff..
   }

   .. more stuff ..

   namespace bar
   {
       ..still more stuff..
   }
};

这个功能的用处很可能在7.3-p4建立之前就已经争论了大约3整秒。

答案 1 :(得分:11)

我在这里不同意其他人的意见。我不会说没有真正的优势。有时我只是想分离代码而没有额外的含义。作为一个例子,我在一个多线程的ringbuffer模块中工作,并希望将状态成员(其中一些是原子和/或内存对齐)拆分为生产者和消费者的命名空间。

通过使用producerconsumer前缀(这是我当前讨厌的实现)命名所有内容,我添加了污染,使代码更难阅读。例如。当生产者拥有的所有东西都以producer开头时,你的大脑在阅读它时会更容易自动更正producerProducerTimer(生产者计时器的生产者副本)为producerConsumerTimer(消费者的生产者影子)计时器)或consumerProducerTimer(生产者计时器的消费者阴影)。调试时间比需要的时间长,因为代码不再可以浏览。

通过创建嵌套的类/结构:

  • 我可以给下一个维护此代码的开发人员提供这样的想法,即在上下文中可以/应该实例化,复制和分配多个这样的代码,所以现在不仅仅是担心命名我也有= delete这些东西。
  • 我可以使用结构对齐填充向上下文添加内存占用,否则可能不需要。
  • 使所有成员都不是一个选项,因为可以实例化多个需要自己的生产者/消费者状态变量的上下文。
  • 此类结构的函数不再能够访问其他成员数据或函数,例如双方共享的常量或函数,而是必须将这些内容作为参数。

理想情况下,我希望能够改变这样的事情:

rbptr producerPosition;
rbptr consumerPosition;

到此:

namespace producer
{
    rbptr position;
}
namespace consumer
{
    rbptr position;
}

然后,只应触及使用者成员的函数可以使用使用者命名空间,只应触及生成者成员的函数可以使用生成器命名空间,而需要触及两者的函数必须明确限定它们。在仅使用生产者名称空间的函数中,无法意外触摸消费者变量。

在这种情况下,希望纯粹是为了减少生产者和消费者副本之间的命名冲突,减少命名冲突是名称空间的存在。出于这个原因,我支持能够在类中声明名称空间的提议。

答案 2 :(得分:8)

在语言中添加这样的功能没有什么好处。除非有需求,否则通常不会添加功能。

课程中的命名空间会给你带来什么?你真的宁愿说binary_tree::iterator::left_depth而不是简单binary_tree::left_depth吗?也许如果你有多个名称空间,你可以使用它们区分说binary_tree::depth_iterator::leftbinary_tree::breadth_iterator::right

无论如何,你可以使用内部类作为一个程序员的命名空间来实现所需的结果,这更是为什么在类中不需要真正的命名空间的原因。

答案 3 :(得分:4)

这不是命名空间的重点。命名空间意味着更接近顶级代码,以便两个不同的公司(或代码库)可以相互混合代码。在更微观的层面上,我使用IMAP进行电子邮件访问和使用SMTP进行电子邮件发送进行编码(可能,我正在极大地简化)在任一模块Email中都有类,这些类是完全不同的,但我可以有一个应用程序比如一个邮件客户端,想要同时使用同一个类,例如也许它会将邮件从一个帐户转发到另一个帐户。命名空间/包名称等允许这样做。

你提出的不仅仅是命名空间的用途 - 在一个文件中你可以给出不同的名字,因为作者具有该文件的全局知识,尽管当两家公司想要共享代码时不是这样。或两个不知道他们会在任何时候碰撞的应用程序。

答案 4 :(得分:1)

我觉得一个小小的想法值得一提。类内部使用命名空间的功能等同于模板化命名空间。

template<class...types>
struct Namespace {
    namespace Implementation {
        ...
    }
};

// somewhere else

using namespace Namespace<types...>::Implementation;

// use templated stuff.

我个人会喜欢此功能,但似乎需求不足以实现它。