在类中声明一个类是有效的。 (嵌套类)
在类中声明命名空间无效。
问题是:是否有任何理由(除了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...
}
如果我使用类而不是命名空间,这是有效的,但是我被迫声明一个永远不会被实例化的类,这是一个非常命名空间。
为什么允许嵌套类并禁止类中的嵌套命名空间?这是传统的负担吗?
具有语义原因的答案不仅引用了标准的一部分(特别是语法部分),而且会引起误解:)
答案 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模块中工作,并希望将状态成员(其中一些是原子和/或内存对齐)拆分为生产者和消费者的命名空间。
通过使用producer
或consumer
前缀(这是我当前讨厌的实现)命名所有内容,我添加了污染,使代码更难阅读。例如。当生产者拥有的所有东西都以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::left
和binary_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.
我个人会喜欢此功能,但似乎需求不足以实现它。