不明瞭な宣言の構文
宣言の構文はオブジェクト宣言としてまたは関数宣言の一部として解釈可能
説明
この欠陥は、オブジェクト宣言と関数/パラメーター宣言のどちらが意図されたものかを宣言から判断できない場合に発生します。このあいまいさは、多くの場合、最も厄介な解析と呼ばれます。
たとえば、以下の宣言はあいまいです。
ResourceType aResource();
aResourceがResourceType型の変数を返す関数なのか、ResourceType型のオブジェクトなのか、すぐには理解できません。TimeKeeper aTimeKeeper(Timer());
aTimeKeeperがTimer型の名前なしオブジェクトで構築されるオブジェクトなのか、パラメーターとして名前なし関数ポインター型をもつ関数なのか、すぐには理解できません。この関数ポインターは、引数がなく戻り値の型がTimerの関数を参照しています。
チェッカーは、グローバル スコープによるあいまいな宣言にフラグを設定します。たとえば、解析では、Type a() の形式を使用したグローバル スコープによる宣言にはフラグが設定されません。ここで、Type は既定のコンストラクターを使用したクラス型です。解析では、a が Type 型を返す関数として解釈されます。
リスク
宣言があいまいな場合、C++ 規格は構文の特定の解釈を選択します。次に例を示します。
- これは関数
ResourceType aResource();
aResourceの宣言として解釈されます。 - これは、関数ポインター型の名前なしパラメーターをもつ関数
TimeKeeper aTimeKeeper(Timer());
aTimeKeeperの宣言として解釈されます。
開発者またはコード レビュー担当者が別の解釈を想定している場合、予期しない結果になる可能性があります。
たとえば、理解するのが困難なコンパイル エラーが後で発生する場合があります。既定の解釈は関数宣言を示すので、この関数をオブジェクトとして使用すると、コンパイラはコンパイル エラーを報告する可能性があります。このコンパイル エラーは、適切なコンストラクターを使用せずに関数からオブジェクトへの変換が試みられていることを示します。
修正方法
宣言を明確にします。たとえば、これらのあいまな宣言は以下のように修正します。
ResourceType aResource();
オブジェクト宣言:
宣言が既定のコンストラクターを使用して初期化されたオブジェクトのことを指している場合は、次のように書き換えます。
これは C++11 より前の場合です。または、次のようにします。ResourceType aResource;
これは、C++11 以降の場合です。ResourceType aResource{};関数宣言:
宣言が関数のことを指している場合、関数の typedef を使用します。
typedef ResourceType(*resourceFunctionType)(); resourceFunctionType aResource;
TimeKeeper aTimeKeeper(Timer());
オブジェクト宣言:
宣言がクラス
Timerの名前なしオブジェクトで初期化されたオブジェクトaTimeKeeperのことを指している場合、かっこのペアを追加します。これは C++11 より前の場合です。または、中かっこを使用します。TimeKeeper aTimeKeeper( (Timer()) );
これは、C++11 以降の場合です。TimeKeeper aTimeKeeper{Timer{}};関数宣言:
宣言が関数ポインター型の名前なしパラメーターをもつ関数
aTimeKeeperのことを指している場合、代わりに名前付きパラメーターを使用します。typedef Timer(*timerType)(); TimeKeeper aTimeKeeper(timerType aTimer);
例
結果情報
| グループ: 適切な手法 |
| 言語: C++ |
| 既定値: オフ |
コマンド ライン構文: MOST_VEXING_PARSE |
| 影響度: Low |
バージョン履歴
R2019a で導入