Ambiguous declaration syntax
Declaration syntax can be interpreted as object declaration or part of function declaration
Description
This defect occurs when it is not clear from a declaration whether an object declaration or function/parameter declaration is intended. The ambiguity is often referred to as most vexing parse.
For instance, these declarations are ambiguous:
ResourceType aResource();
It is not immediately clear if
aResource
is a function returning a variable of typeResourceType
or an object of typeResourceType
.TimeKeeper aTimeKeeper(Timer());
It is not immediately clear if
aTimeKeeper
is an object constructed with an unnamed object of typeTimer
or a function with an unnamed function pointer type as parameter. The function pointer refers to a function with no argument and return typeTimer
.
The checker does not flag ambiguous declarations with global scope. For instance, the
analysis does not flag declarations with global scope using the format
Type a()
where
Type
is a class type with a default constructor. The
analysis interprets a
as a function returning the type
Type
.
Risk
In case of an ambiguous declaration, the C++ Standard chooses a specific interpretation of the syntax. For instance:
- is interpreted as a declaration of a function
ResourceType aResource();
aResource
. - is interpreted as a declaration of a function
TimeKeeper aTimeKeeper(Timer());
aTimeKeeper
with an unnamed parameter of function pointer type.
If you or another developer or code reviewer expects a different interpretation, the results can be unexpected.
For instance, later you might face a compilation error that is difficult to understand. Since the default interpretation indicates a function declaration, if you use the function as an object, compilers might report a compilation error. The compilation error indicates that a conversion from a function to an object is being attempted without a suitable constructor.
Fix
Make the declaration unambiguous. For instance, fix these ambiguous declarations as follows:
ResourceType aResource();
Object declaration:
If the declaration refers to an object initialized with the default constructor, rewrite it as:
prior to C++11, or as:ResourceType aResource;
after C++11.ResourceType aResource{};
Function declaration:
If the declaration refers to a function, use a typedef for the function.
typedef ResourceType(*resourceFunctionType)(); resourceFunctionType aResource;
TimeKeeper aTimeKeeper(Timer());
Object declaration:
If the declaration refers to an object
aTimeKeeper
initialized with an unnamed object of classTimer
, add an extra pair of parenthesis:prior to C++11, or use braces:TimeKeeper aTimeKeeper( (Timer()) );
after C++11.TimeKeeper aTimeKeeper{Timer{}};
Function declaration:
If the declaration refers to a function
aTimeKeeper
with a unnamed parameter of function pointer type, use a named parameter instead.typedef Timer(*timerType)(); TimeKeeper aTimeKeeper(timerType aTimer);
Examples
Result Information
Group: Good practice |
Language: C++ |
Default: Off |
Command-Line Syntax:
MOST_VEXING_PARSE |
Impact: Low |
Version History
Introduced in R2019a
See Also
Variable shadowing
| Non-initialized variable
| Write without a further read
| Improper array initialization
| Find defects (-checkers)
Topics
- Interpret Bug Finder Results in Polyspace Desktop User Interface
- Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access)
- Address Results in Polyspace User Interface Through Bug Fixes or Justifications
- Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access)