Most vexing parse
The most vexing parse is a specific form of syntactic ambiguity resolution in the C++ programming language. The term was used by Scott Meyers in Effective STL (2001).[1] It is formally defined in section 8.2 of the C++ language standard.[2]
Example with classes
An example is:
class Timer {
public:
Timer();
};
class TimeKeeper {
public:
TimeKeeper(const Timer& t);
int get_time();
};
int main() {
TimeKeeper time_keeper(Timer());
return time_keeper.get_time();
}
The line
TimeKeeper time_keeper(Timer());
is seemingly ambiguous, since it could be interpreted either as
- a variable definition for variable
time_keeper
of classTimeKeeper
, initialized with an anonymous instance of classTimer
or - a function declaration for a function
time_keeper
that returns an object of typeTimeKeeper
and has a single (unnamed) parameter that is a pointer to function returning an object of typeTimer
(and taking no input). (See Function object#In C and C++)
Most programmers expect the first, but the C++ standard requires it to be interpreted as the second.
For example, g++ gives the following error message:
$ g++ -c time_keeper.cc
time_keeper.cc: In function ‘int main()’:
time_keeper.cc:15: error: request for member ‘get_time’ in ‘time_keeper’, which is
of non-class type ‘TimeKeeper(Timer (*)())’
Notice that the compiler gives the error message about the return statement of main()
: since it interpreted the declaration of time_keeper
as a function declaration we won't be able to call the member function get_time()
on this.
Clang++ provides a warning:
$ clang++ time_keeper.cc timekeeper.cc:14:25: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse] TimeKeeper time_keeper(Timer()); ^~~~~~~~~ timekeeper.cc:14:26: note: add a pair of parentheses to declare a variable TimeKeeper time_keeper(Timer()); ^ ( ) timekeeper.cc:15:21: error: member reference base type 'TimeKeeper (Timer (*)())' is not a structure or union return time_keeper.get_time(); ~~~~~~~~~~~^~~~~~~~~
The common ways to force the compiler to consider this as a variable definition are:
- To add an extra pair of parentheses:
TimeKeeper time_keeper((Timer()));
- To use copy initialization:
TimeKeeper time_keeper = TimeKeeper(Timer());
- (In C++11 and later.) To use uniform initialization with braces:
TimeKeeper time_keeper{Timer()};
TimeKeeper time_keeper(Timer{});
TimeKeeper time_keeper{Timer{}};
Example with functions
An even simpler example appears when a functional cast is intended to convert an expression for initializing a variable or passing to a constructor parameter
void f(double adouble) {
int i(int(adouble));
}
In this case, the parentheses around adouble
are superfluous and the declaration of i
is again a function declaration equivalent to the following
// takes an integer and returns an integer
int i(int adouble);
To disambiguate this in favour of a variable declaration, the same technique can be used as for the first case above. Another solution is to use the cast notation:
// declares a variable called 'i'
int i((int) adouble);
Or also to use a named cast:
// declares a variable called 'i'
int i(static_cast<int>(adouble));
Uniform initialization syntax
Using the new uniform initialization syntax introduced in C++11 solves this issue.
The problematic code is then unambiguous when braces are used:
TimeKeeper time_keeper{Timer{}};
Using braces as above creates a variable definition for variable time_keeper
of class TimeKeeper
, initialized with an anonymous instance of class Timer
.
References
- Meyers, Scott (2001). Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library. Addison-Wesley. ISBN 0-201-74962-9.
- ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §8.2 Ambiguity resolution [dcl.ambig.res]
External links
- Amazing feats of Clang Error Recovery LLVM Project Blog
- C++'s "most vexing parse" ars technica
- Uniform initialization syntax and semantics