It is possible to devise syntax that can ambiguously be interpreted as either an expression statement or a declaration. Syntax of this sort is called a vexing parse because the compiler must use disambiguation rules to determine the semantic results. The C++ Standard, [stmt.ambig], paragraph 1 [ISO/IEC 14882-2014], states in part, states the following:
There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a
(
. In those cases the statement is a declaration. [Note: To disambiguate, the whole statement might have to be examined to determine if it is an expression-statement or a declaration. ...
A similarly vexing parse exists within the context of a declaration where syntax can be ambiguously interpreted as either a function declaration or a declaration with a function-style cast as the initializer. The C++ Standard, [dcl.ambig.res], paragraph 1, states in part, states the following:
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration.
...
In this compliant solution, the lock object is given an identifier (other than m
) and the proper converting constructor is called:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <mutex> static std::mutex m; static int shared_resource; void increment_by_42() { std::unique_lock<std::mutex> lock(m); shared_resource += 42; } |
...
Parentheses around parameter names are optional, so the following is a semantically identical spelling of the declaration:.
Code Block | ||||
---|---|---|---|---|
| ||||
Gadget g(Widget i); |
...
This compliant solution demonstrates two equally compliant ways to write the declaration of g
. The first declaration, g1
, uses an extra set of parentheses around the argument to the constructor call, forcing the compiler to parse this it as a local variable declaration of type Gadget
instead of as a function declaration. The second declaration, g2
, uses direct initialization to similar effect.
...
Running this program produces the expected output:.
Widget constructed
Gadget constructed
Widget constructed
Gadget constructed
3
...