This is a Most Vexing Parse issue. The canonical case would be:
T t( U(x) );
where T and U are previously known to be type names. This could be parsed in two valid ways:
- a declaration of
t
as an object of type T
, with the initializer being the expression U(x)
, a function-style cast of the variable x
to a temporary U
- a declaration of
t
as a function returning T
, with 1 parameter of type U
and name x
; and there are redundant parentheses around x
. (Declarators may be parenthesized).
The text in the Standard for disambiguating is in [dcl.ambig.res]/1. What it says is that parsing this code hinges on whether U(x)
would be a declaration or an expression, and then refers to [stmt.ambig].
In [stmt.ambig]/2 there is a clarifying example. I won't reproduce the full example here (you can look it up in a standards draft) but the accompanying text is:
If the statement cannot syntactically be a declaration, there is no ambiguity
[...] This is of course ill-formed for semantic reasons, but that does not affect the syntactic analysis. In those cases the statement is a declaration.
What this is trying to say is that if the code can be matched to the rules in the language grammar for a declaration, then it is a declaration, even if the code subsequently falls foul of a semantic rule.
Looking at your variation now, where the inner code is (simplified) U(A::e)
where e
is an enumerator in the scope of A
.
I believe this code does still match the grammar rule for a declaration. See [dcl.decl]/4 grammar specification (selected parts):
noptr-declarator: declarator-id attribute-specifier-seqopt
declarator-id: ...opt id-expression
and id-expression can be qualified-id or unqualified-id, and finally, A::e
is a qualified-id.
Even though there is a semantic rule [dcl.meaning]/1 that the declarator-id can only be a qualified-id in certain contexts, excluding this case, that's not a grammar rule.
So I would say VC is correct to reject the code.
To fix the code, assuming the intent is for a2
to be an object declaration, you can use the same techniques as mentioned on the canonical MVP thread:
A a2{A::B(A::eA2)}; // braced initialization
A a2((A::B(A::eA2))); // function declarations can't have extra parentheses around the entire parameter declaration, so this cannot be a function declaration