Search code examples
c++visual-c++compiler-errorscompiler-bug

Forward defining class in namespace?


The following snippet fails to compile with Visual Studio 2010, but GCC likes it:

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 ()
{
}

Am I doing something stupid here or is this a valid compiler bug? The error I get is: error C2888: 'void Bar::Foo(void)' : symbol cannot be defined within namespace 'Test'

It compiles with GCC 4.5.1: http://ideone.com/7sImY

[Edit] Just to be clear, I want to know if this is valid C++ or not (and if so, why not) -- workarounds to get it compiled are nice but not part of this question.


Solution

  • I think the code is well-formed. But proving that for certain would require making sure there's nothing in the Standard that contradicts the usage.

    Some relevant quotes from the C++11 Standard:

    3.3.2 p6:

    The point of declaration of a class first declared in an elaborated-type-specifier is as follows:

    • for an elaborated-type-specifier of the form class-key identifier
      • if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a function defined in namespace scope, the identifier is declared as a class-name in the namespace that contains the declaration; otherwise, except as a friend declaration, the identifier is declared in the smallest non-class, non-function-prototype scope that contains the declaration.

    3.4.4 p2:

    If the elaborated-type-specifier has no nested-name-specifier, and unless the elaborated-type-specifier appears in a declaration with the following form: class-key attribute-specifier-seq opt identifier ; the identifier is looked up according to 3.4.1 but ignoring any non-type names that have been declared. ... If the elaborated-type-specifier is introduced by the class-key and this lookup does not find a previously declared type-name, or if the elaborated-type-specifier appears in a declaration with the form: class-key attribute-specifier-seq opt identifier ; the elaborated-type-specifier is a declaration that introduces the class-name as described in 3.3.2.

    7.1.6 has some syntax definitions establishing that an elaborated-type-specifier can syntactically be a type-specifier. 7.1 establishes that a type-specifier can syntactically be a decl-specifier, which is the syntactical unit used as the type in a function parameter-declaration (8.3.5).