式のセマンティクス
式は、式の演算子の優先順位とグループ化に従って評価されます (構文規則における演算子の優先順位と結合規則は、C++ の演算子が式に適用する関係を示します)。
評価の順序
次の例について考えます。
// Order_of_Evaluation.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main()
{
int a = 2, b = 4, c = 9;
cout << a + b * c << "\n";
cout << a + (b * c) << "\n";
cout << (a + b) * c << "\n";
}
38
38
54
式-評価順序
上の図に示す式が評価される順序は、演算子の優先順位と結合規則によって決まります。
この式では、乗算 (*) が最も高い優先順位を持ちます。したがって、部分式
b * cが最初に評価されます。次に優先順位が高いのは加算 (+) であるため、
aとbの積にcが加算されます。左シフト ( << ) は、式の中で最も低い優先順位を持ちますが、2回出現します。 左シフト演算子は左から右にグループ化されるため、左の部分式が最初に評価され、次に右の部分式が評価されます。
かっこを使用して部分式がグループ化されている場合は、優先順位が変更されるため、次の図に示すように、式の評価順序も変更されます。
式-かっこを使用した評価順序
上の図のような式は、 — 標準出力デバイスに情報を転送するために、この場合の副作用に対して純粋に評価されます。
式の表記
C++ 言語では、オペランドを指定するときに、特定の互換性を指定します。 型のオペランドを必要とする演算子に対して許容されるオペランドの型を次の表に示します。
演算子に適切なオペランドの型
| 型が必要です | 許可される型 |
|---|---|
| type | constconstvolatilevolatile各種 constconst&volatilevolatile&volatile constvolatile constvolatile constvolatile const& |
| 各種 | 各種constconst *volatilevolatile *volatile constvolatile const * |
constconst |
typeconstconstconstconst& |
volatilevolatile |
typevolatilevolatilevolatilevolatile& |
前の規則はいつでも組み合わせて使用できるため、volatile オブジェクトへの const ポインターは、ポインターが想定される場所で指定できます。
あいまいな式
状況によっては、式の意味があいまいになる場合があります。 通常、オブジェクトの値が同じ式で複数回変更されると、このような式が発生します。 これらの式は、評価の特定の順序に依存します (言語が定義しない場合)。 次の例を考えてみましょう。
int i = 7;
func( i, ++i );
C++ 言語では、関数呼び出しの引数が評価される順序は保証されません。 したがって、前の例では、左から右、右から左のどちらの方向でパラメーターが評価されるかに応じて、func はパラメーターとして値 7 と 8、または 8 と 8 を受け取ります。
C++ シーケンスポイント (Microsoft 固有)
式では、連続する "シーケンス ポイント" 間で、オブジェクトの値を一度だけ変更できます。
C++ 言語の定義では、現在シーケンス ポイントは指定されていません。 Microsoft C++ では、C の演算子を伴い、オーバーロードされた演算子を伴わないすべての式に、ANSI C と同じシーケンス ポイントを使用します。 演算子がオーバーロードされている場合、セマンティクスは演算子のシーケンスから関数呼び出しのシーケンスに変更されます。 Microsoft C++ は、次のシーケンス ポイントを使用します。
論理 AND 演算子 () の左オペランド && 。 論理 AND 演算子の左オペランドは完全に評価され、すべての副作用は続行の前に完了します。 論理 AND 演算子の右オペランドが評価される保証はありません。
論理 OR 演算子 (||) の左オペランド。 論理 OR 演算子の左オペランドは完全に評価され、すべての副作用は続行の前に完了します。 論理 OR 演算子の右オペランドが評価される保証はありません。
コンマ演算子の左オペランド。 コンマ演算子の左オペランドは完全に評価され、すべての副作用は続行の前に完了します。 コンマ演算子のオペランドは両方とも、常に評価されます。
関数呼び出し演算子。 関数呼び出し式と、関数の既定の引数も含めたすべての引数は、評価され、すべての副作用は関数に入る前に完了します。 引数や関数呼び出し式の間に、指定された評価順序はありません。
条件演算子の最初のオペランド。 条件演算子の最初のオペランドは完全に評価され、すべての副作用は続行の前に完了します。
初期化式全体の最後 (宣言ステートメントでの初期化終了時など)。
式ステートメント内の式。 式ステートメントは、省略可能な式とそれに続くセミコロン (;) で構成されます。 式の副作用は完全に評価されます。
選択 (if または switch) ステートメント内の制御式。 式は完全に評価され、すべての副作用は選択に依存するコードが実行される前に完了します。
while または do ステートメントの制御式。 式は完全に評価され、すべての副作用は while または do ループの次のイテレーションのステートメントが実行される前に完了します。
for ステートメントの 3 つの各式。 各式は完全に評価され、すべての副作用は次の式に移動する前に完了します。
return ステートメント内の式。 式は完全に評価され、すべての副作用は呼び出し元の関数に制御が戻る前に完了します。