Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Deleted blank Related Guidelines section; minor edits

It is possible to devise syntax which that can ambiguously be interpreted as either an expression statement or a declaration. Syntax of this sort is referred to as called vexing parse because the compiler must use disambiguation rules to determine the semantic results. The C++ Standard, [stmt.ambig], paragraph 1, states in part [ISO/IEC 14882-2014]:

...

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:

...

Do not write a syntactically ambiguous declaration, including vexing parses. With the advent of uniform initialization syntax using a braced-init-list, there is now syntax that unambiguously specifies a declaration instead of an expression statement. Declarations can also be disambiguated by using nonfunction-style casts, initialization by initializating using =, or by removing extraneous parenthesis around the parameter name.

...

In this noncompliant code example, an attempt is made to declare a local variable, w, of type Widget while executing the default constructor. However, this is syntactically ambiguous where the code could be either be a declaration of a function pointer accepting no arguments and returning a Widget, or a declaration of a local variable of type Widget. The syntax used in this example defines the former instead of the latter.

...

As a result, this program compiles and prints no output , because the default constructor is never actually invoked.

...

This compliant solution shows two equally - compliant ways to write the declaration. The first way is to elide the parenthesis parentheses after the variable declaration; this , which ensures the syntax is that of a variable declaration instead of a function declaration. The second way is to use a braced-init-list to direct-initialize the local variable.

Code Block
bgColor#ccccff
langcpp
#include <iostream>
 
struct Widget {
  Widget() { std::cout << "Constructed" << std::endl; }
};

void f() {
  Widget w1; // Elide the parenthesisparentheses
  Widget w2{}; // Use direct initialization
}

Running this program produces the output Constructed.

Noncompliant Code Example

This noncompliant code example demonstrates a vexing parse. The declaration Gadget g(Widget(i)); is not parsed as declaring a Gadget object with a single argument, but . It is instead parsed as a function declaration with a redundant set of parenthesis parentheses around a parameter. 

Code Block
bgColor#FFCCCC
langcpp
#include <iostream>

struct Widget {
  explicit Widget(int I) { std::cout << "Widget constructed" << std::endl; }
};

struct Gadget {
  explicit Gadget(Widget wid) { std::cout << "Gadget constructed" << std::endl; }
};

void f() {
  int i = 3;
  Gadget g(Widget(i));
  std::cout << i << std::endl;
}

...

As a result, this program is well-formed and prints only 3 as output , because no Gadget or Widget objects are constructed.

...

This compliant solution demonstrates two equally - compliant ways to write the declaration of g. The first declaration, g1, uses an extra set of parenthesis parentheses around the argument to the constructor call, forcing the compiler to parse this as a local variable declaration of type Gadget instead of as a function declaration. The second declaration, g2, uses direct initialization to similar effect.

Code Block
bgColor#ccccff
langcpp
#include <iostream>

struct Widget {
  explicit Widget(int I) { std::cout << "Widget constructed" << std::endl; }
};

struct Gadget {
  explicit Gadget(Widget wid) { std::cout << "Gadget constructed" << std::endl; }
};

void f() {
  int i = 3;
  Gadget g1((Widget(i))); // Use extra parenthesisparentheses
  Gadget g2{Widget(i)}; // Use direct initialization
  std::cout << i << std::endl;
}

...

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

DCL53-CPP

Low

Unlikely

Medium

P2

L3

Automated Detection

Tool

Version

Checker

Description

 PRQA QA-C++

Include Page
PRQA QA-C++_V
PRQA QA-C++_V

2510

 
Clang
Include Page
Clang_V
Clang_V
-Wvexing-parse 

...

Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

...

Bibliography

[ISO/IEC 14882-2014]6.8, "Ambiguity resolution"
8.2, "Ambiguity resolution"
[Meyers 01]Item 6, "Be alert for C++'s most vexing parse"

...