C++ 将内部类名声明为另一个声明的一部分

C++ 将内部类名声明为另一个声明的一部分,c++,language-lawyer,C++,Language Lawyer,在试图用pimpl习惯用法定义一个类时,我试图通过将类前向声明滚动到pimpl定义中来保存一行代码 class A { public: class Impl *pimpl; }; 上述声明汇编得很好。不起作用的是试图定义A::Impl: 结果是: 错误:限定名未在“{”标记之前命名类 现在,我们可以通过一个复杂的类型说明符引入一个新的类名,作为另一个声明的一部分 为什么在它自己的行上的前向声明(如惯用用法)会引入a::Impl,但在作为指针定义的一部分声明时,会引入::Impl 更新

在试图用pimpl习惯用法定义一个类时,我试图通过将类前向声明滚动到pimpl定义中来保存一行代码

class A
{
public:
    class Impl *pimpl;
};
上述声明汇编得很好。不起作用的是试图定义
A::Impl

结果是:

错误:限定名未在“{”标记之前命名类

现在,我们可以通过一个复杂的类型说明符引入一个新的类名,作为另一个声明的一部分

为什么在它自己的行上的前向声明(如惯用用法)会引入
a::Impl
,但在作为指针定义的一部分声明时,会引入
::Impl

更新

我不是问如何让这个成语起作用,我的问题是为什么要用单行

class Impl *pimpl;
不具有与两行相同的效果

class Impl;
Impl *pimpl;
在类定义的上下文中

class A
{
public:
    class Impl *pimpl;
};
我很困惑,因为这个名字在使用时就被正确地限定了


稍微更改您的
A
声明:

class A
{
public:
    class Impl;

    Impl *pimpl;
};
现在,一切都将按预期进行

首先,您必须告诉编译器,
Impl
是一个内部类

class A
{
public:
    class Impl *pimpl;
};

这告诉编译器,
pimpl
是一个指向名为
Impl
的顶级类的指针,而不是一个内部类。

好吧,标准像往常一样提供了一个答案。并明确要求它

引述第2款(empahsis矿):

如果详细类型说明符没有嵌套的名称说明符,则为,除非详细类型说明符以以下形式出现在声明中:

类键属性说明符seqopt标识符

根据[basic.lookup.unqual]查找标识符,但忽略已声明的任何非类型名称
(…)
如果详细类型说明符是由类键引入的,并且此查找未找到以前声明的类型名称,或者如果详细类型说明符以以下形式出现在声明中:

类键属性说明符seqopt标识符

详细说明的类型说明符是一个声明,它引入了类名称,如[basic.scope.pdecl]中所述

和第7段(再次强调):

在详细的类型说明符中首先声明的类的声明点如下:

--申请表格的声明

类键属性说明符seqopt标识符

标识符被声明为包含该声明的作用域中的类名,否则

--对于窗体的详细类型说明符

类密钥标识符

如果在命名空间范围中定义的函数的decl说明符seq或参数声明子句中使用了详细的类型说明符,则标识符将在包含该声明的命名空间中声明为类名;否则,除了作为友元声明外,标识符将在最小的名称中声明包含声明的espace或block作用域[注意:这些规则也适用于模板。-结束说明][注意:其他形式的详细类型说明符不声明新名称,因此必须引用现有类型名称。请参阅[basic.lookup.elab]和[dcl.type.elab]。-结束说明]

最后一行强调的声明似乎是指出现详细类说明符的类的声明。因此,在我们的示例中,它将
Impl
添加到包含类
A
的命名空间中,即全局范围。但这同样适用于任何命名空间:


我知道如何使它按预期工作。这不是我的问题。我想我应该删除
pimpl
标记。
class A
{
public:
    class Impl;

    Impl *pimpl;
};
class A
{
public:
    class Impl *pimpl;
};
namespace E
{
    class A
    {
        class Impl *pImpl;  
    };
}

class E::Impl
{

};

int main() {
    // your code goes here
    return 0;
}