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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13484387/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:22:53  来源:igfitidea点击:

Why can't we declare a namespace within a class?

c++classnamespaces

提问by Drax

Declaring a class within a class is valid. (Nested classes)

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

Declaring a namespace within a class is invalid.

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

The question is: is there any good reason (other than c++ grammar/syntax problems) to forbid the declaration of a namespace within a class ?

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



As for why would i want to do that, here is an exemple :

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

Let's have a basic delcaration of a binary tree container

让我们有一个二叉树容器的基本声明

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

Now i notice that there are a lot of iterators in my class, so i would like to regroup them within the same namespace like this :

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

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

This would allow a simple usage :

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

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

  ...stuff...
}

This works if i use a class instead of a namespace, but i am then forced to declare a class that will never be instantiated which is quite a namespace.

如果我使用一个类而不是命名空间,这会起作用,但是我被迫声明一个永远不会被实例化的类,这是一个相当的命名空间。

Why allow nested classes and forbid nested namespaces within classes ? is it a legacy burden ?

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



Answers with semantic reasons that do not only quote part of the standard(especially syntax parts) will be apreciated :)

不仅会引用部分标准(尤其是语法部分)的语义原因的答案将受到赞赏:)

采纳答案by Adrian McCarthy

There's no real advantage to adding such a feature to the language. Features generally don't get added unless there's demand.

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

What would namespaces inside classes buy you? Would you really rather say binary_tree::iterator::left_depthinstead of simply binary_tree::left_depth? Perhaps if you had multiple namespaces inside, you use them to distinguish say binary_tree::depth_iterator::leftand binary_tree::breadth_iterator::right.

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

In any event, you can achieve the desired result using internal classes as a poor-programmer's namespace, which is even more reason why there isn't demand for true namespaces inside classes.

在任何情况下,您都可以使用内部类作为一个糟糕的程序员的命名空间来实现预期的结果,这也是为什么在类中不需要真正的命名空间的更多原因。

回答by WhozCraig

Since you asked which parts of the standard mandate namespace location, we hit that up first:

由于您询问了标准授权命名空间位置的哪些部分,我们首先提出了这个问题:

C++11 7.3-p4:Every namespace-definition shall appear in the global scope or in a namespace scope (3.3.6).

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

Regarding class definitions and the proposition of declaring a namespace within, I bring you to...

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

C++11 9.2-p2:A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

C++11 9.2-p2:在类说明符的结尾 } 处,类被视为完全定义的对象类型 (3.9)(或完整类型)。在类成员规范中,类在函数体、默认参数、异常规范和非静态数据成员(包括嵌套类中的此类内容)的括号或相等初始化器中被视为完整的。否则在它自己的类成员规范中被认为是不完整的。

Ergo, a class definition is finite once the closing curly is reached. It cannot be opened back up and extended (derivation is something different, but it is NOT extending the class just defined).

因此,一旦达到闭合卷曲,类定义就是有限的。它不能被打开和扩展(派生是不同的,但它不是扩展刚刚定义的类)。

But lurking at the very beginning of the standard definition of a namespace is the ability to extend it; to expand it for lack of a better term:

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

C++ 7.3-p1:A namespace is an optionally-named declarative region. The name of a namespace can be used to access entities declared in that namespace; that is, the members of the namespace. Unlike other declarative regions, the definition of a namespace can be split over several parts of one or more translation units.(emphasis added).

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

Therefore, a namespace within a class would violate the definition in 7.3-p4. Assuming that was not present, it would be possibleto declare a namespace anywhere, including in a class, but since the definition of a class is formalized once it is closed, you would be left with only the ability to do the following if you maintained compliance with 7.3-p1:

因此,类中的命名空间将违反 7.3-p4 中的定义。假设不存在,这将是可能的声明命名空间的任何地方,包括在一类,但因为一个类的定义形式化一旦关闭,你会只剩做到以下几点,如果你维护的能力符合 7.3-p1:

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

   .. more stuff ..

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

The usefulness of this featurewas likely debated for about 3-full-seconds before 7.3-p4 was established to settle it.

在 7.3-p4 被建立来解决这个问题之前,这个功能的有用性可能被争论了大约 3 秒。

回答by ErsatzStoat

I'm going to disagree with others here. I wouldn't say there's no real advantage. Sometimes I'd just like to segregate code without extra implications. As an example, I was working in a multithreaded ringbuffer module and wanted to split the state members, some of which are atomic and/or memory-aligned, into namespaces for the producer and the consumer.

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

By just naming everything with produceror consumerprefixes (which is my current annoying implementation), I'm adding pollution that makes code harder to read. E.g. when everything owned by the producer starts with producer, it's easier for your brain when reading it to accidentally autocorrect producerProducerTimer(producer copy of a producer timer) as producerConsumerTimer(producer shadow of a consumer timer) or consumerProducerTimer(consumer shadow of a producer timer). Debugging that takes way longer than it needs to because the code is no longer skimmable.

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

By creating a nested class/struct:

通过创建嵌套类/结构:

  • I could be giving the next developer who maintains this code the idea that more than one of these could/should be instantiated, copied, and assigned to one another within a context, so now instead of just worrying about naming I also have to = deletethese things.
  • I could be adding memory footprint to the context with structural alignment padding that might not otherwise be necessary.
  • Making all members static isn't an option, since more than one context can be instantiated that will need its own producer/consumer state variables.
  • Functions of such a struct no longer have access to other member data or functions, such as constants or functions that are shared by both sides, but instead have to take these things as arguments.
  • 我可以让下一个维护此代码的开发人员认为,其中不止一个可以/应该在上下文中实例化、复制和分配给另一个,所以现在除了担心命名之外,我还必须处理= delete这些事情.
  • 我可以使用结构对齐填充向上下文添加内存占用,否则可能不需要。
  • 将所有成员设为静态不是一种选择,因为可以实例化多个上下文,这些上下文需要自己的生产者/消费者状态变量。
  • 这种结构体的函数不再可以访问其他成员数据或函数,例如双方共享的常量或函数,而是必须将这些东西作为参数。

Ideally, I'd like to be able to change things like this:

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

rbptr producerPosition;
rbptr consumerPosition;

to this:

对此:

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

Then, functions that should only touch consumer members can use the consumer namespace, functions that should only touch the producer members can use the producer namespace, and functions that need to touch both have to explicitly qualify them. There'd be no way to accidentally touch a consumer variable in a function that's only using the producer namespace.

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

In this case, the desire is purely for reducing naming collisions between producer and consumer copies of things, and reducing naming collisions are what namespaces exist for. For that reason, I support the proposal to be able to declare namespaces inside classes.

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

回答by djechlin

This is just not the point of namespaces. Namespaces are meant to exist closer to the top level of code so that if two different companies (or code bases) can mix code with each other. At a more micro level, I code with both IMAP for email access and SMTP for email sending and (could, I am simplifying greatly) have classes in either module called Emailthat are quite different, but I could have an application, say a mail client, that wants to use both from the same class, e.g. perhaps it forwards mails from one account to another. Namespaces / package names / etc. permit this.

这不是命名空间的重点。命名空间旨在靠近代码的顶层,以便两个不同的公司(或代码库)可以相互混合代码。在更微观的层面上,我使用用于电子邮件访问的 IMAP 和用于电子邮件发送的 SMTP 进行编码,并且(可能,我正在极大地简化)在任何一个模块Email中都有非常不同的类,但我可以有一个应用程序,比如邮件客户端,想要使用来自同一类的两者,例如,它可能将邮件从一个帐户转发到另一个帐户。命名空间/包名/等允许这一点。

What you have proposed simply isn't what namespaces are for - within one file you are able to give things different names since the author has global knowledge of the file, although this isn't true when two companies want to share code or two applications that didn't know they would be colliding at any point.

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

回答by Anthony Monterrosa

Just a small thought that I felt was worth mentioning. One use of namespaces inside of classes would be a functional equivalent to templated namespaces.

只是我觉得值得一提的一个小想法。在类中使用命名空间的一种用途是在功能上等效于模板化命名空间。

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

// somewhere else

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

// use templated stuff.

Personally, I would enjoy this feature, but it seems the demand isn't high enough for it to be implemented.

就我个人而言,我会喜欢这个功能,但似乎需求不够高,无法实现。