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

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

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

问题是:除了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...
}

如果我使用类而不是名称空间,则此方法有效,但随后我被迫声明一个永远不会实例化的类,这是一个相当大的名称空间。

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


带有语义原因的答案不仅会引用标准的一部分(尤其是语法部分),因此将不胜感激:)

Drax asked 2020-07-25T22:25:06Z
5个解决方案
46 votes

由于您询问了标准任务名称空间位置的哪些部分,因此我们首先介绍一下:

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..
   }
};

在建立7.3-p4来解决此功能之前,可能已经争论了大约3个整整秒钟的时间来使用此功能。

WhozCraig answered 2020-07-25T22:26:38Z
14 votes

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

通过仅用= deleteconsumer前缀(这是我当前烦人的实现)命名所有内容,我添加了使代码难以阅读的污染。 例如。 当生产者拥有的所有内容都以producer开头时,您的大脑会更容易意外地将producerProducerTimer(生产者计时器的生产者副本)自动更正为producerProducerTimer9972(消费者计时器的生产者影子)或producerProducerTimer9973(生产者计时器的消费者影子) 。 调试所花费的时间比所需的时间长,因为代码不再是可略读的。

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

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

理想情况下,我希望能够更改以下内容:

rbptr producerPosition;
rbptr consumerPosition;

对此:

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

然后,仅应与使用者成员接触的函数可以使用使用者命名空间,仅应与生产者成员接触的函数可以使用生产者命名空间,而需要两者接触的函数必须显式限定它们。 在仅使用生产者名称空间的函数中,无法无意间触及使用者变量。

在这种情况下,纯粹是希望减少事物的生产者和消费者副本之间的命名冲突,并且减少命名冲突是存在命名空间的目的。 因此,我支持能够在类内部声明名称空间的建议。

ErsatzStoat answered 2020-07-25T22:27:45Z
8 votes

在语言中添加这样的功能并没有真正的优势。 除非有需求,否则通常不会添加功能。

类中的名称空间会给您带来什么? 您是否真的想说binary_tree::iterator::left_depth,而不是简单地说binary_tree::left_depth? 也许如果内部有多个名称空间,则可以使用它们来区分binary_tree::depth_iterator::leftbinary_tree::breadth_iterator::right

无论如何,您都可以使用内部类作为不良程序员的名称空间来获得所需的结果,这甚至是为什么在类内部不需要真正的名称空间的更多原因。

Adrian McCarthy answered 2020-07-25T22:25:41Z
4 votes

这只是名称空间的重点。 命名空间应该存在于更接近代码顶层的位置,以便两个不同的公司(或代码库)可以将代码相互混合。 在更微观的层面上,我既使用IMAP进行电子邮件访问,也使用SMTP进行电子邮件发送,并且(可以简化,我可以)在两个模块中的类称为Email,它们有很大的不同,但是我可以拥有一个应用程序,例如邮件 想要使用同一个类的客户端,例如 也许它将邮件从一个帐户转发到另一个帐户。 命名空间/程序包名称/等等。

您所提议的根本不是名称空间的用途-在一个文件中,您可以赋予不同的名称,因为作者具有文件的全局知识,尽管当两家公司想要共享代码或两个应用程序时,情况并非如此 不知道他们会在任何时候发生冲突。

djechlin answered 2020-07-25T22:28:10Z
1 votes

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

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

// somewhere else

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

// use templated stuff.

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

Anthony Monterrosa answered 2020-07-25T22:28:35Z
translate from https://stackoverflow.com:/questions/13484387/why-cant-we-declare-a-namespace-within-a-class