在名称空间中转发定义类?

时间:2011-11-09 19:11:01

标签: c++ visual-c++ compiler-errors compiler-bug

以下代码段无法使用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 ++(如果是这样,为什么不呢) - 编译它的变通方法很好但不是这个问题的一部分。

4 个答案:

答案 0 :(得分:2)

好吧,我也在codepad.org尝试了它并且它编译了,但我不确定它是否应该(不精通C ++编译器功能)!

解决方法:也可以转发声明Bar,或者在制作Bar之前必须定义Foo。换句话说,这在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;
}

<强>更新 我认为这可能已经是向微软报告的错误...这看起来非常接近: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). 

答案 1 :(得分:1)

可能是编译错误。

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

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

答案 2 :(得分:1)

我认为代码格式正确。但事实证明,确保标准中没有任何内容与使用相矛盾。

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

3.3.2 p6:

  

首先在 elaborated-type-specifier 中声明的类的声明点如下:

  • 表示 class-key identifier 形式的详细类型说明符
    • 如果在 decl-specifier-seq 参数声明子句中使用 elaborated-type-specifier 在命名空间作用域中定义的函数,标识符在命名空间中声明为类名 包含声明;否则,除了作为朋友声明之外,标识符在声明中声明 包含声明的最小的非类,非函数原型范围。

3.4.4 p2:

  

如果 elaborated-type-specifier 没有嵌套名称说明符,除非elaborated-type-specifier出现在具有以下形式的声明中:    class-key attribute-specifier-seq opt identifier ;   根据3.4.1查找标识符,但忽略已声明的任何非类型名称。 ...如果引入了 elaborated-type-specifier    class-key 并且此查找找不到先前声明的 type-name ,或者 elaborated-type-specifier   出现在具有以下形式的声明中:    class-key attribute-specifier-seq opt identifier ;    elaborated-type-specifier 是一个声明,它引入了 class-name ,如3.3.2所述。

7.1.6有一些语法定义确定 elaborated-type-specifier 在语法上可以是类型说明符。 7.1确定类型说明符在语法上可以是 decl-specifier ,它是在函数 parameter-declaration (8.3.5)。

答案 3 :(得分:-2)

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

Anywho,你需要在测试中定义Bar和Baz:

namespace Test {
    class Bar;
    class Baz;
};

在声明函数参数时,请删除classstructunionenum个关键字。

通过这种修改,它可以在g ++ 4.6中完全编译。