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

Dra*_*rax 44 c++ namespaces class

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

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

问题是:是否有任何好的理由(除了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;
};
Run Code Online (Sandbox Code Playgroud)

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

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;
};
Run Code Online (Sandbox Code Playgroud)

这将允许一个简单的用法:

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

  ...stuff...
}
Run Code Online (Sandbox Code Playgroud)

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

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


具有语义原因而不仅引用部分标准(特别是语法部分)的答案将是apreciated :)

Who*_*aig 46

既然你问过标准命令命名空间位置的哪些部分,我们首先点击它:

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

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

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

因此,一旦达到收尾卷曲,类定义就是有限的.它不能打开备份和扩展(派生是不同的,但它不是扩展刚刚定义的类).

但潜伏在命名空间标准定义的最开始的是扩展它的能力; 为了缺乏一个更好的术语来扩展它:

C++ 7.3-p1:命名空间是一个可选命名的声明性区域.命名空间的名称可用于访问在该命名空间中声明的实体; 也就是命名空间的成员.与其他声明性区域不同,命名空间的定义可以分为一个或多个转换单元的几个部分.(重点补充).

因此,类中的命名空间将违反7.3-p4中的定义.假设不存在,可以在任何地方声明一个命名空间,包括在一个类中,但由于一个类的定义一旦关闭就形式化了,如果你维护它,你将只能做以下事情.符合7.3-p1:

class Foo
{
   namespace bar
   {
       ..stuff..
   }

   .. more stuff ..

   namespace bar
   {
       ..still more stuff..
   }
};
Run Code Online (Sandbox Code Playgroud)

在建立7.3-p4以解决它之前,这个特征的有用性可能会争论大约3整秒.

  • 嗯,那是纯粹的技术性.您可以在extensibility子句中添加一个异常,说明只能扩展类范围之外的名称空间.十分简单. (3认同)
  • “在 7.3-p4 被建立来解决这个问题之前,这个功能的有用性可能已经争论了大约 3 秒。” 讨论并不完全是如何进行的。讨论将变成关于 7.3-p4 本身是否有意义的讨论。没有 7.3-p4 的命名空间将是一个比有 7.3-p4 更强大的工具,这是这里提出的整个论点。 (2认同)

Ers*_*oat 14

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

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

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

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

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

rbptr producerPosition;
rbptr consumerPosition;
Run Code Online (Sandbox Code Playgroud)

对此:

namespace producer
{
    rbptr position;
}
namespace consumer
{
    rbptr position;
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我确实赞同这个观点,标记的答案被标记为已接受,因为它确实回答了"为什么现在不是这样"的问题,主要答案是"你可以用另一个功能做得不好,所以没有人提出这个" ,这并不意味着它必须保持这种方式,我也会支持这样的提议,有人做的那天:) (3认同)

Adr*_*thy 8

将这样的功能添加到语言中没有任何实际优势.除非有需求,否则通常不会添加功能.

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

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

  • "除非有需求,否则通常不会增加功能." 我们*正在谈论C++,对吗? (64认同)
  • 对于一个类在命名空间中使用某些东西作为某种东西的"它"版本的模板,它会很有用.例如T :: Namespace :: EnumValue (3认同)
  • 在类的内部和外部,名称空间(几乎)完全是语法糖。那么,为什么要塞姆呢? (2认同)
  • 当您不想混淆名称相似的变量(因为它们做类似的事情,但是在代码中的不同位置)时,这将很有用。当然,总是有不同的方法来实现这一点,但是当您不想为此使用额外的结构时,类内的名称空间将是一个简单的解决方案。 (2认同)
  • @einpoklum:_“命名空间(几乎)完全是语法糖,无论是在类内还是类外。那么为什么要拥有它们呢?”_ 当然,让我们回到扁平、脆弱、笨拙、不完整、不灵活、过于冗长、重复的话题(等等)“VOLUNTARY_NAMING_CONVENTIONS”和“Static::items::for::scoping”)而不是正确的、编译器支持的、“语义的”、灵活的(等等)“真实的”命名空间。 (2认同)