The most vexing parse is a counterintuitive form of syntactic ambiguity resolution in the C++ programming language. In certain situations, the C++ grammar cannot distinguish between the creation of an object parameter and specification of a function's type. In those situations, the compiler is required to interpret the line as a function type specification.
A simple example appears when a functional cast is intended to convert an expression for initializing a variable:
voidf(doublemy_dbl){inti(int(my_dbl));}
Line 2 above is ambiguous. One possible interpretation is to declare a variablei with initial value produced by convertingmy_dbl to an int. However, C allows superfluous parentheses around function parameter declarations; in this case, the declaration of i is instead a function declaration equivalent to the following:
// A function named i takes an integer and returns an integer.inti(intmy_dbl);
is ambiguous, since it could be interpreted either as
a variable definition for variable time_keeper of class TimeKeeper, initialized with an anonymous instance of class Timer or
a function declaration for a function time_keeper that returns an object of type TimeKeeper and has a single (unnamed) parameter, whose type is a (pointer to a) function[Note 1] taking no input and returning Timer objects.
The C++ standard requires the second interpretation, which is inconsistent with the subsequent line 10 above. For example, Clang++ warns that the most vexing parse has been applied on line 9 and errors on the subsequent line 10:[3]
$ clang++ time_keeper.cc
timekeeper.cc:9:25: warning: parentheses were disambiguated as a function declaration[-Wvexing-parse]
TimeKeeper time_keeper(Timer());
^~~~~~~~~timekeeper.cc:9:26: note: add a pair of parentheses to declare a variable
TimeKeeper time_keeper(Timer());
^( )timekeeper.cc:10:21: error: member reference base type 'TimeKeeper (Timer (*)())' is not astructure or union
return time_keeper.get_time();
~~~~~~~~~~~^~~~~~~~~
Solutions
The required interpretation of these ambiguous declarations is rarely the intended one.[4][5] Function types in C++ are usually hidden behind typedefs and typically have an explicit reference or pointer qualifier. To force the alternate interpretation, the typical technique is a different object creation or conversion syntax.
In the type conversion example, there are two alternate syntaxes available for casts: the "C-style cast"
// declares a variable of type intinti((int)my_dbl);
or a named cast:
inti(static_cast<int>(my_dbl));
In the variable declaration example, the preferred method (since C++11) is uniform (brace) initialization.[6] This also allows limited omission of the type name entirely:
//Any of the following work:TimeKeepertime_keeper(Timer{});TimeKeepertime_keeper{Timer()};TimeKeepertime_keeper{Timer{}};TimeKeepertime_keeper({});TimeKeepertime_keeper{{}};
Prior to C++11, the common techniques to force the intended interpretation were use of an extra parenthesis or copy-initialization:[5]
^According to C++ type decay rules, a function object declared as a parameter is equivalent to a pointer to a function of that type. See Function object#In C and C++.
References
^Meyers, Scott (2001). Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library. Addison-Wesley. ISBN0-201-74962-9.
^DrPizza; Prototyped; wb; euzeka; Simpson, Homer J (October 2002). "C++'s "most vexing parse"". ArsTechnica OpenForum. Archived from the original on 20 May 2015. Retrieved 2021-01-17.
^Stroustrup, Bjarne (19 August 2016). "C++11 FAQ". www.stroustrup.com. Uniform initialization syntax and semantics. Archived from the original on 2021-08-20. Retrieved 2021-01-17.