Search code examples
c++c++11visual-c++visual-studio-2015strongly-typed-enum

Usage of members of a strongly typed enum in a member function's default arguments


I am using G++ mostly and nowadays Visual Studio 2015. I wanted to build my project with VC++2015 but I get error messages that saying invalid use of '::' in a function given default arguments with a forward declared strongly typed enum.

Here is some code:

struct Foo
{
    //! Forward declaration of Bar
    enum class Bar : short;

    //! "Faulty" function with default argument
    void DoSmth(Bar aBar = Bar::Baz)
    {
        // ... code ...
    }

    //! Complete declaration of Bar
    enum class Bar : short
    {
        Baz
    };
};

int main() { }

It gives me the following error at the declaration of the function DoSmth() with the default argument Bar::Baz:

test.cpp(7): error C2589: '::': illegal token on right side of '::'
test.cpp(7): error C2059: syntax error: '::'
test.cpp(17): fatal error C1903: unable to recover from previous error(s); stopping compilation

With G++ (tested with 4.9 and 5.1) the code compiles just fine but with VC++2015 it doesn't.

Im fully aware that I have to declare something before usage but. Is it just because that VC++2015 does not look within the scope of the class for the complete declaration and definition of Bar but G++ does? Or maybe does G++ just take the complete declaration and "merges" it with the forward declaration (as they are in the same scope) and thus makes it completely available to the class? Or maybe I am just plain wrong and something complete different causes this?

I can live with it that I have to change all my declarations for strongly typed enums in order to make it work with VC++2015.

But I also want to know why this is?


Solution

  • Your code is valid, and VC 14 is wrong to reject it.

    According to N4527, the current Standard working draft, [9.2p2]:

    A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

    Within the default argument, finding Bar::Baz requires the full definition of Bar, which is available in the complete class, so everything's fine.