在命名空间中向前定义类

Forward defining class in namespace?

本文关键字:定义 命名空间      更新时间:2023-10-16

下面的代码片段无法在Visual Studio 2010中编译,但是GCC喜欢它:

namespace Test { 
    class Baz;
    // Adding class Bar; here and removing the class below makes it work
    // with VC++, but it should work like this, shouldn't it?
    void Foo (Baz& b, class Bar& c);
}
namespace Test { 
    class Bar
    {
        // Making this method non-template works
        template <typename T>
        static void Lalala ()
        {
        }
    };
}
int main ()
{
}

我在这里做了一些愚蠢的事情还是这是一个有效的编译器错误?我得到的错误是:error C2888: 'void Bar::Foo(void)' : symbol cannot be defined within namespace 'Test'

使用GCC 4.5.1编译:http://ideone.com/7sImY

[编辑]只是为了清楚,我想知道如果这是有效的c++或不(如果是这样,为什么不)-变通方法得到它编译是很好的,但不是这个问题的一部分。

嗯,我在codepad.org上也试过了,它可以编译,但我不确定它应该(不是那么精通c++编译器功能)!

解决方法:也向前声明Bar,或者在创建Foo之前必须定义Bar。换句话说,这在MSVC中编译:

namespace Test 
{ 
    class Baz;
    class Bar;// also forward-declare Bar
    void Foo (Baz& b, class Bar& c);
}
namespace Test 
{ 
    class Bar
    {
        template <typename T>
        static void Foo ()
        {
        }
    };
}
int main(void)
{
    return 0;
}

更新:我想这可能已经是向微软报告的bug了……这看起来很接近:http://connect.microsoft.com/VisualStudio/feedback/details/99218/invalid-error-c2888-when-a-class-is-defined-after-it-is-declared

Microsoft引用的变通方法:

A stand-alone forward declaration consists of an elaborated type specifier followed by a semicolon.
insert the declaration
class C2888;
before the declaration of foo(C2888o, C2888). 

我认为代码格式良好。但要证明这一点,就需要确保标准中没有任何与用法相矛盾的内容。

c++ 11标准中的一些相关引用:

3.3.2 p6:

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

  • 用于类键标识符形式的详细类型说明符
      如果详细类型说明符decl- specific -seq参数声明子句中使用了,则
    • 在命名空间作用域中定义的函数,标识符在命名空间中声明为类名包含声明;否则,除了作为友元声明外,标识符在包含声明的最小非类、非函数原型范围。

3.4.4 p2:

如果精心设计的类型说明符没有嵌套的名称说明符,并且除非精心设计的类型说明符以以下形式出现在声明中:class-key attribute-specifier-seq opt identifier ;标识符根据3.4.1查找,但忽略已声明的任何非类型名称. ...如果精心设计的类型说明符是由类键和此查找没有找到先前声明的类型名称,或者如果详细类型说明符出现在声明中,格式为:class-key attribute-specifier-seq opt identifier ;详细类型说明符是一个声明,它引入了3.3.2中描述的类名

7.1.6有一些语法定义,建立了详细类型说明符在语法上可以是类型说明符。7.1规定类型说明符在语法上可以是decl说明符,这是在函数参数声明(8.3.5)中用作类型的语法单位。

可能是编译器错误。

改变参数的顺序将改变编译结果。

namespace Test { 
void Foo (class Bar& b, class Baz& c) - will compile.
}

class Bar结构是错误的。你是一个没有使用typedef struct { /* members */ } Foo的C程序员吗?

无论如何,您需要在test中定义Bar和Baz:

namespace Test {
    class Bar;
    class Baz;
};

并在声明函数参数时删除classstructunionenum关键字。