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?
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.