为什么我不能在头文件中单独编写命名空间层次结构?

4

我写了一些头文件。我想分别声明命名空间层次结构(以增加清晰度),然后再声明函数和类。对我来说,它看起来像文档中的目录。这对我来说非常方便:可以在一个地方看到所有命名空间的完整层次结构。我写了这个:

// Namespaces hierarchy:
namespace Bushman{
    namespace CAD_Calligraphy{}
    //...
}

// Declarations of classes and functions
class Bushman::CAD_Calligraphy::Shp_ostream{
public:
    explicit Shp_ostream(std::ostream& ost);
};

但是 MS Visual Studio 对这种创建头文件的方式表示不赞同。我应该这样写:
namespace Bushman{
    namespace CAD_Calligraphy{
        class Shp_istream{
        public:
            explicit Shp_istream(std::istream& ist);
        };
    }
}

为什么第一种变量不起作用?这是C++的限制还是IDE的限制?

P.S. 我的附加问题在这里

谢谢。


1
据我所知,这是C++的限制 - 我从未在实际代码中见过“第一种变体”。 - SigTerm
4个回答

10

限制在§9/1中: "如果一个类头名称包含嵌套名称限定符,则类说明符必须引用在该嵌套名称限定符所引用的类或命名空间中先前直接声明过的类[...]". 换句话说,类名的第一次出现不能像Bushman::CAD_Calligraphy::Shp_ostream那样。

您可以在层次结构的初始声明中添加前向声明来解决问题:

// Namespaces hierarchy:
namespace Bushman{
    namespace CAD_Calligraphy{
        class Shp_ostream;
        //...
    }
    //...
}

// Declarations of classes and functions
class Bushman::CAD_Calligraphy::Shp_ostream{
public:
    explicit Shp_ostream(std::ostream& ost);
};

根据您的标题组织方式,从人类的角度来看,这可能会更好:您的标题以某种定义的索引开始。


2
引用标准:第7.3.1.2点2节。

Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration’s namespace.

namespace Q {
  namespace V
    void f();
  }
  void V::f() { /∗ ... ∗/ }    // ok. 
  void V::g() { /∗ ... ∗/ }    // Error: g() is not yet a member of V
  namespace V
    void g();
  }
}

namespace R {
   void Q::V::g() { /∗ ... ∗/ }   // // error: R doesn’t enclose Q
}

所以,如果你在原始帖子中声明类名,你可以做你原来想做的:

namespace Bushman{
    namespace CAD_Calligraphy {
        class Shp_ostream;
        ...
    }
}

1

我可以帮忙翻译,这段内容与编程有关。它提到了C++的工作方式。

它与其他嵌套声明一致:你不能从类外部添加成员到一个类中:

class A
{
};

void A::f() { }  // Error!

你无法从外部向枚举类型添加枚举器:

enum E { E1 = 1, E2 = 2 };

E::E3 = 3;  // Error!

你需要“打开”作用域并在作用域内声明实体。一旦它被声明,你可以使用嵌套名称在该作用域之外定义它:

class A
{
  void f();  // declare
};

void A::f() { }  // define

-1

首先,C++并不是设计成这样工作的。所以这种情况发生并不奇怪。

但是,由于您正在使用Visual Studio,您可以利用部分类。不幸的是,似乎这个特性只与C++/CX相关,所以您可能无法使用它。

您仍然需要在命名空间层次结构中声明一个部分类,但我想它可能是空的。

老实说,我没有使用过这个功能,也不知道它能够达到您想要的程度。但是您可以尝试一下。

请记住,这是Visual Studio扩展,因此您的代码将无法跨平台。

希望这能在某种程度上对您有所帮助。


2
这不是“设计成那样工作”的问题,而是标准中的任意限制。(对于“任意”一词的某些含义。可能在引入它时,有人有理由这样做。) - James Kanze
抱歉,更改了链接。感谢您的提醒,@DyP。无论如何,创建部分类的可能性似乎与C++/CX密切相关,因此OP可能无法使用它。 - Baltasarq
@James Kanze,不理解您的评论。C++中的命名空间机制是设计为以某种特定方式运行的(您甚至在您的答案中引用了标准文本),显然它不接受OP想要的行为。另一个问题是是否可以这样做/已经这样做了。 - Baltasarq
@Baltasarq 不允许OP想要做的事情是一种限制。对我来说,现在看起来有点武断,但我猜至少有一个委员会成员觉得这样做是有充分理由的(并且说服了其他人)。 - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接