Cannot create class as LHS value with qualified enum as argument (C ++ VS2015)

I'm a little surprised to see this compilation error;

Here's an example:

class A
{
public:
  enum eA { eA1, eA2 };

  class B
  {
  public:
    B(eA e, int i = 0);
  };

  A(const B &b);
};

A::A(const B &b)
{
}

A::B::B(eA e, int i /*= 0*/)
{
}

int main()
{
  A::B b(A::eA1);        // OK
  A a0(b);               // OK
  A a1(A::B(A::eA1, 0)); // OK
  A a2(A::B(A::eA2));    //error C2751: 'A::eA2': the name of a function parameter cannot be qualified
  return 0;
}

      

As pointed out in the comments, A a2(A::B(A::eA2));

does not compile. What for? I am not asking how to compile it. Why won't it compile?

It compiles if the first type of the class- parameter does B

not belong to the class A

. for example, with int

it compiles.

+3


source to share


1 answer


This is a problem with a lot of disassembly. The canonical case would be as follows:

T t( U(x) );

      

where T and U were previously known as type names. This could be analyzed in two valid ways:

  • declaration t

    as an object of type t

    , and the initializer is an expression U(x)

    , casting a function into a variable x

    to a temporaryU

  • declaration t

    as a function, returning t

    , with 1 type parameter U

    and name x

    ; and there are copied parentheses around x

    . (Declarators can be bracketed.)

The text in the Standard for disambiguation is at [dcl.ambig.res] / 1. He says that parsing this code depends on whether it is a U(x)

declaration or an expression, and then refers to [stmt.ambig].

There is an illustrative example in [stmt.ambig] / 2. I won't reproduce the full example here (you can see it in the standards draft), but the accompanying text:

If a statement cannot syntactically be a declaration, there is no ambiguity

[...] This is of course ill-formed for semantic reasons, but it does not affect parsing. In these cases, the assertion is a declaration.

What this is trying to say is that if the code can be matched against the rules in the grammar of the language for the declaration, then that declaration, even if the code subsequently fails to match the semantic rule.




Now let's look at your variation, where is the inner code (simplified) U(A::e)

, where e

is the enumerator in the scope A

.

I believe this code still follows the grammar rule for the declaration. See [Dcl.decl] / 4 grammar specification (separate parts):

noptr-declarator: declarator-id attribute-specifier-seq opt

declarator-id: ... opt id-expression

and id-expression can be a qualified id or unqualified-id, and is finally A::e

a qualified identifier.

Even though there is a semantic rule [dcl.meaning] / 1 that a declarator identifier can only be a qualified identifier in certain contexts, except in this case, it is not a grammar rule.

So, I would say that VC rejects the code correctly.




To fix the code, assuming the goal a2

is to declare an object, you can use the same methods mentioned in the MVP canonical 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 

      

+2


source







All Articles