【问题标题】:Header files without explicitly writing namespace没有显式写入命名空间的头文件
【发布时间】:2015-11-11 12:05:42
【问题描述】:

在 C++ 实现文件中,我可以选择编写如下内容:

name::space::ClassName::someFunction(int param) {
    // impl
}

而不是

namespace name {
    namespace space {
        ClassName::someFunction(int param) {
            // impl
        }
    }
}

我觉得非常方便且更具可读性。这也可以在头文件中使用吗?像这样的:

class name::space::ClassName {
    // declarations
};

而不是

namespace name {
    namespace space {
        class ClassName {
            // declarations
        };
    }
}

如果这样的事情是可能的,那么在什么条件下?我可以想象,需要 forward 声明命名空间 向前声明命名空间中的类,如下所示:

namespace name {
    namespace space {
        class ClassName;
    }
}

在能够使用它之前:

class name::space::ClassName {
    // declarations
};

在头文件中。

但不知何故,我无法让它工作1]。甚至可能吗?困扰我的是,对于嵌套的命名空间,我必须缩进 2 个制表符,直到我可以真正声明我的类。我想在我的头文件中使用该空间,但我不想省略制表符,因为这违反了“大括号中的所有内容都需要制表符一次”的规则(我不知道是否有一个实际的名字。如果有,请原谅我的无知,我不知道:S

1] 我遇到的问题与问题无关。该方法确实有效,但有缺点(请参阅已接受的答案)。

【问题讨论】:

  • with nested namespaces I have to indent 2 tabs 你并没有真正,这是关于你的编码约定。例如,在我工作的所有地方,我们都不会为嵌套命名空间添加额外的缩进。
  • 该制表规则的一种混合形式是在一行中使用namespace name { namespace space {,其余的只用一个制表符缩进,然后以} }结束
  • @SingerOfTheFall 哪个(=不缩进命名空间)我认为这是一件非常明智的事情。
  • 问题是name::space:: 引用 命名空间name 下定义了另一个命名空间space。它没有定义它。
  • 是的,我知道我可以内联编写它,但不知何故我不太喜欢它。我非常了解统一约定,其中还包括我的命名空间

标签: c++


【解决方案1】:

如果您只是不希望命名空间大括号包围您的类定义,您当然可以通过在其他地方定义命名空间并仅在其中包含类声明来实现这一点。这样,你可以想出这样的东西:

#ifndef MYCLASS_H
#define MYCLASS_H

namespace ClassNamespace { class MyClass; };

class ClassNamespace::MyClass
{
public:
    MyClass();
    ~MyClass();
    void a();
private:

};

#endif // MYCLASS_H

对于标题和这个:

#include "MyClass.h"

#include <iostream>

using namespace std;

ClassNamespace::MyClass::MyClass()
{
}

ClassNamespace::MyClass::~MyClass()
{
}

void ClassNamespace::MyClass::a()
{
    cout << "hello";
}

用于实施。

如您所见,命名空间并未包含类定义,仅包含其声明。

最后一点,我个人不知道您为什么要这样做,或者认为它看起来更好读。我个人更愿意看到命名空间封装类定义以及函数定义。但也许我一直都是个奇怪的人……

【讨论】:

  • 很难解释为什么我更喜欢它。如果我不想在使用封装的命名空间时省略制表符,我会发现它更具可读性。对你的回答:所以这真的有用吗?我真的更喜欢这种方法。此外,如果我使用一个专用标头来定义项目的所有名称空间,我可以更好地记录它们(仅在一个位置,而不是在使用名称空间关键字的每个位置)。另一方面,缺点很明显;您必须维护另一个文件并将其包含在任何地方...
  • 这当然是一个有趣的想法。这样,您基本上可以在一个地方查看所有类及其所属的命名空间。或者可能是每个文件的命名空间。我真的不认为这是标准约定,但肯定很有趣。我想我不会介意的。
  • 更新:虽然我喜欢这个想法,但我不得不承认将命名空间存储在单独的文件中是不切实际的。如果一个类被删除、替换或重命名,则无法保证开发人员记得删除该类不需要的前向声明。这最终会使命名空间文件膨胀......无论如何,我按照你的建议更改了我的代码,在类的顶部使用了内联命名空间和类前向声明​​。这对我来说是最好的折衷方案,这样如果我有嵌套的命名空间,我可以保持我的缩进使用并且不必缩进两次。感谢所有的回答和帮助
【解决方案2】:

不,它不起作用。一个问题是

namespace name {
    namespace space {
        class ClassName {
            // declarations
        }
    }
}

你可以看出它是两个命名空间和一个类。

然而,与

class name::space::ClassName {
    // declarations
}

您无法判断space 是命名空间还是包含嵌套ClassName 的类。

可以做的是保存在你的标签上。可以写

namespace name { namespace space {
    class ClassName {
        // declarations
    }
}}

【讨论】:

  • 啊有趣,我没有考虑嵌套类。无论如何,如果我转发声明命名空间,那么它不应该是模棱两可的,对吧?为什么它无论如何都不起作用? (见底部OP)
【解决方案3】:

你正在寻找的东西不起作用。

一种解释是所有 C++ classstruct 类型都隐含地与它们自己的命名空间(与类同名)相关联。

所以,给定

class name::space::ClassName
{
// declarations
};

编译器无法确定namespace 是否实际上是命名空间或类(充其量只能断定该构造是不明确的)。所以编译器需要被明确告知name 是一个命名空间,spacename 中的一个命名空间,然后才被告知ClassName 是其中的一个类。

因此需要

namespace name
{
    namespace space
    {
        class ClassName;
    }
}

转发指定两个命名空间并在其中转发声明ClassName

【讨论】:

  • 是的,我现在了解出现的问题。我没有考虑这个。但是,如果我转发声明命名空间,它不应该是模棱两可的,所以编译器可以解决这个问题?
  • 命名空间不是“前向声明的”,类和结构是。但是,为了做你想做的事,有必要在命名空间中转发声明类,正如 Elephly 所展示的那样。
  • 我修正了 OP 中的错误术语,感谢您让我意识到这一点。
【解决方案4】:

不,这是不可能的。 定义命名空间的唯一方法是将namespace关键字与花括号结合使用。

7.3.1 命名空间定义 [namespace.def]

1 命名空间定义的语法是

  namespace-name:
      original-namespace-name
      namespace-alias
  original-namespace-name:
      identifier
  namespace-definition:
      named-namespace-definition
      unnamed-namespace-definition
  named-namespace-definition:
      original-namespace-definition
      extension-namespace-definition
  original-namespace-definition:
      inlineopt namespace identifier { namespace-body }
  extension-namespace-definition:
      inlineopt namespace original-namespace-name { namespace-body }
  unnamed-namespace-definition:
      inlineopt namespace { namespace-body }
  namespace-body:
      declaration-seqopt

您可以在命名空间之外定义命名空间的成员,尽管它必须在namespace声明(强调我的):

7.3.1.2 命名空间成员定义 [namespace.memdef]

2 命名命名空间的成员也可以通过显式限定在该命名空间之外定义 (3.4.3.2) 正在定义的名称,前提是正在定义的实体已经在命名空间中声明 并且定义出现在包含声明的命名空间中的声明点之后 命名空间。

当你写作时

namespace name {
    namespace space {
        class ClassName;
    }
}

您没有在namespace space 中声明class ClassName,您只是提供了一个前向声明

【讨论】:

  • 这没有回答问题,即在类定义中指定命名空间。
  • @interjay 现在好点了吗?
  • 是的,好多了。但是,OP 说他试图在定义它之前在命名空间中声明该类并且它不起作用。
  • @interjay 我认为问题在于他没有将类声明到命名空间中,但他只是转发声明了它。
  • 严格来说,没有“转发”这样的声明-声明。它要么是声明,要么是定义。所以class MyClass; 是一个类声明,这就足够了。
猜你喜欢
  • 2011-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 2013-09-29
相关资源
最近更新 更多