170

Among the many things Stack Overflow has taught me is what is known as the "most vexing parse", which is classically demonstrated with a line such as

A a(B()); //declares a function 

While this, for most, intuitively appears to be the declaration of an object a of type A, taking a temporary B object as a constructor parameter, it's actually a declaration of a function a returning an A, taking a pointer to a function which returns B and itself takes no parameters. Similarly the line

A a(); //declares a function 

also falls under the same category, since instead of an object, it declares a function. Now, in the first case, the usual workaround for this issue is to add an extra set of brackets/parenthesis around the B(), as the compiler will then interpret it as the declaration of an object

A a((B())); //declares an object 

However, in the second case, doing the same leads to a compile error

A a(()); //compile error 

My question is, why? Yes I'm very well aware that the correct 'workaround' is to change it to A a;, but I'm curious to know what it is that the extra () does for the compiler in the first example which then doesn't work when reapplying it in the second example. Is the A a((B())); workaround a specific exception written into the standard?

10
  • 20
    (B()) is just a C++ expression, nothing more. It's not any kind of exception. The only difference that it makes is that there's no way it can be possibly parsed as a type, and so it's not. Commented Sep 15, 2009 at 0:32
  • 12
    It should also be noted that the second case, A a(); is not of the same category. For the compiler, there is never any different way to parse it: An initializer at that place never consists of empty parentheses, so this is always a function declaration. Commented Sep 15, 2009 at 2:08
  • 11
    litb's excellent point is a subtle yet important one and is worth emphasizing - the reason the ambiguity exists in this declaration 'A a(B())' is in the parsing of 'B()' -> it can be both an expression & a declaration & the compiler must 'pick' decl over expr - so if B() is a decl then 'a' can only be a func decl (not a variable decl). If '()' was allowed to be an initializer 'A a()' would be ambiguous - but not expr vs decl, but var decl vs func decl - there is no rule to prefer one decl over another - and so '()' is just not allowed as an initializer here - and the ambiguity does not rise. Commented Sep 15, 2009 at 4:29
  • 6
    A a(); is not an example of the most vexing parse. It is simply a function declaration, just like it is in C. Commented Mar 27, 2013 at 11:32
  • 2
    "the correct 'workaround' is to change it to A a;" is wrong. That won't give you initialization of a POD type. To get intitialization write A a{};. Commented Sep 1, 2017 at 17:33

4 Answers 4

73

There is no enlightened answer, it's just because it's not defined as valid syntax by the C++ language... So it is so, by definition of the language.

If you do have an expression within then it is valid. For example:

 ((0));//compiles 

Even simpler put: because (x) is a valid C++ expression, while () is not.

To learn more about how languages are defined, and how compilers work, you should learn about Formal language theory or more specifically Context Free Grammars (CFG) and related material like finite state machines. If you are interested in that though the wikipedia pages won't be enough, you'll have to get a book.

Sign up to request clarification or add additional context in comments.

2 Comments

Even simpler put: because (x) is a valid C++ expression, while () is not.
I've accepted this answer, in addition Pavel's comment to my initial question helped me out a lot
41

The final solution to this issue is to move to the C+11 uniform initialization syntax if you can.

A a{}; 

http://www.stroustrup.com/C++11FAQ.html#uniform-init

Comments

12

You could instead

A a(()); 

use

A a=A(); 

1 Comment

The 'better workaround' is not equivalent. int a = int(); initializes a with 0, int a; leaves a uninitialized. A correct workaround is to use A a = {}; for aggregates, A a; when default-initialization does what you want, and A a = A(); in all other cases -- or just use A a = A(); consistently. In C++11, just use A a {};
6

The innermost parens in your example would be an expression, and in C++ the grammar defines an expression to be an assignment-expression or another expression followed by a comma and another assignment-expression (Appendix A.4 - Grammar summary/Expressions).

The grammar further defines an assignment-expression as one of several other types of expression, none of which can be nothing (or only whitespace).

So the reason you can't have A a(()) is simply because the grammar doesn't allow it. However, I can't answer why the people who created C++ didn't allow this particular use of empty parens as some sort of special-case - I'd guess that they'd rather not put in such a special case if there was a reasonable alternative.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.