Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

The Most Vexing Parse

Last updated Jan 1, 2003.

C++ has parsing ambiguity between a function declaration and a constructor invocation when the constructor arguments are temporaries. This is known as the "most vexing parse" problem. C++09 doesn't resolve this ambiguity but there are several things you can do to avert it in the first place. Awareness is the first step.

The Problem

How would you interpret the last line of code in the following listing?

struct S {
     S();
};
struct T {
  T(const S& );
};
T v( S() );    //what's your interpretation?

Most programmers interpret the last line as a definition of an object v of type T which is initialized with a temporary S object. Indeed, several old compilers still interpret the code in this manner. However, the construct S() in a declaration context can also be an abstract declarator (a declarator without an identifier) meaning: a function with no parameters returning S by value. In that case, the construct S() is implicitly converted to the function pointer S(*)(). The entire statement T v( S() ) therefore can therefore mean a declaration of a function called v having a parameter of function-pointer type, and returning a value of type T.

In programming languages, there's rarely any true ambiguity. The parser has precedence rules that disambiguate what otherwise may seem as ambiguous statements. The statement

T v( S() );    //what's your interpretation?

is interpreted as a function declaration, not as a definition of an object because of a parsing precedence rule called "favor a declaration" which basically says: When a well-formed C++ statement can be interpreted as either a declaration or something else (a definition, an expression etc.), favor a declaration. You're already familiar with another parsing disambiguation rule called the maximal munch rule. We can thus conclude that

T v( S() );

Is a declaration of a function called v, not an object definition. Surprised? Confused? So are several C++ compilers. Now let's see how to resolve this issue.

Manual Disambiguation

By now you know that code containing the most vexing parse isn't really ambiguous. However, a human reader might find it ambiguous or even misinterpret it, assuming that the statement

T v( S() );

is a definition. The best approach is defensive programming -- avoid the seemingly ambiguous syntax in the first place. If you want to initialize an object, use an extra pair of parentheses:

T v( (S()) );  // v is an object initialized by a reference to a temporary

If you want to declare a function having a parameter of function-pointer type that returns a value of type T, use the following syntax instead:

T v( S(*)() ); // v is a function

As always, typedefs can simplify complex declarations.

C++09 and Quality of Implementation

You're probably wondering why the C++09 standard doesn't address the most vexing parse issue. The primary reason is that overriding the default interpretation (i.e., favoring an object initialization to a function declaration) might cause existing code to break. That said, using the new initialization syntax of C++09 you can easily make your intention clear:

T v={ S() };

Of course, traditional assignment syntax will also do the trick:

T v= S();

Although the latter is suspected of being less efficient because it might introduce unnecessary temporaries (in practice, compiler' should optimize away these temporaries).

Official C++ imposes no requirements on compilers with respect to the most vexing parse. However, several compilers issue diagnostics when they encounter such statements. The Apple-sponsored Clang compiler produces the following warning:

warning: parentheses were disambiguated as a function declarator
    T v( S() );
       ^~~~~~~

Sun's Studio 12 C++ 5.9 compiler requires the +w option to issue a warning in this case but its warning is much clearer:

Warning: Declaration of "v" is a function, not an object.

Hopefully, a similar warning will become the default in the presence of the most vexing parse even if the C++ standard doesn't require this.