スイッチに関して、規格は次のように述べています。 "switchステートメントが実行されると、その条件が評価され、各ケース定数と比較されます。"
条件式が一度だけ評価され、各コンパイラの標準によって保証されているということですか?
たとえば、関数がswitchステートメントヘッドで使用されている場合、副作用があります。
int f() { ... }
switch (f())
{
case ...;
case ...;
}
f
が1回だけ呼び出されることが保証されていると思います。
まず、
条件は、整数型、列挙型、またはクラス型でなければなりません。
[6.4.2(1)](非整数のものはここでは適用されません)、および
式である条件の値は、式の値です。
[6.4(4)]。さらに、
条件の値は、使用法が明確である場合、単に「条件」と呼ばれます。
[6.4(4)]つまり、この場合、「条件」はint
ではなく、タイプf
の単純な値です。 f
は、条件の値を見つけるためにのみ使用されます。制御がswitch
ステートメントに到達すると
その状態が評価されます
[6.4.2(5)]、つまり、int
によって返されるf
の値を「条件」として使用します。そして最後に、条件(int
ではなく、タイプf
の値)は次のようになります。
各ケース定数と比較
[6.4.2(5)]。これにより、f
からの副作用が再び発生することはありません。
N3797からのすべての引用。 (N4140もチェック、違いなし)
読書 N4296
ページ10パラ14:
完全式に関連するすべての値の計算と副作用は、評価される次の完全な式に関連するすべての値の計算と副作用の前にシーケンスされます。
パラグラフの最初の行を読んだとき。 10(その上):
完全式は、別の式の部分式ではない式です。
switch
ステートメントの条件は完全な式であり、各条件式は完全な式であると信じる必要があります(実行時には些細なことですが)。
switch
は式ではなくステートメントです(6.4.2および他の多くの場所を参照)。
したがって、それを読み取ることにより、switch
の評価は、case
定数の評価の前に行われる必要があります。
相変わらず多くのポイントは、明白な結論に達するために仕様の曲がりくねった読みに要約されます。
その文を査読した場合、次の修正案を提案します(bold):
Switchステートメントが実行されると、その条件がswitchステートメントの実行ごとに1回評価され、各ケース定数と比較されます。
はい、式はswitchステートメントの実行時に1回だけ評価されます。
§6.4選択ステートメント
4 [...]式である条件の値は、式の値です[...]条件の値は、使用法が明確である場合、単に「条件」と呼ばれます。
これは、式が評価され、その値が各condition
ステートメントに対して評価されるcase
と見なされることを意味します。
このコードはhello
を1回または2回出力しますか?
int main() {
printf("hello\n");
}
答えは、特定のswitch
ステートメントの文言ではなく、標準が何を記述しているかをより一般的に理解することにあると思います。
プログラム実行[intro.execution]のように、標準はいくつかの動作を記述します抽象マシンそれ実行 C++に従って解析されたプログラム- 文法。 「抽象マシン」または「実行」が何を意味するかを実際に定義するわけではありませんが、それらは明白なコンピュータサイエンスの概念、つまり抽象構文ツリーを通過し、によって記述されたセマンティクスに従ってそのすべての部分を評価するコンピュータを意味すると想定されます。標準。これは、何かを1回記述した場合、executionがそのポイントに到達すると、1回だけ評価されることを意味します。
より適切な質問は、「実装がプログラムで記述された方法ではない何かを評価する可能性がある場合」です。このために、あたかもルールと、実装がこの抽象的な解釈から逸脱することを可能にする未定義の動作の束があります。
セクション6.4.4:
...式である条件の値は、式の値であり、switch以外のステートメントの場合はコンテキストでboolに変換されます。..条件の値は、使用法では単に「条件」と呼ばれます。明確です
私の理解では、上記の引用は次の擬似コードと同等です。
switchCondition := evaluate(expression)
今あなたの見積もりを追加します
...その状態が評価され、各ケース定数と比較されます。
これは次のように翻訳する必要があります。
foreach case in cases
if case.constant == switchCondition
goto case.block
そうそう、これが事実のように見えます。
制御の流れによって一度だけ評価される式が保証されます。これは、標準N4431§6.4.2/ 6で正当化されます。switchステートメント[stmt.switch](Emphasis mine) :
caseラベルとdefaultラベル自体は制御の流れを変更せず、そのようなラベル間で妨げられることなく継続します。スイッチを終了するには、break、6.6.1を参照してください。 [注:通常、切り替えの対象となるサブステートメントは複合であり、大文字と小文字およびデフォルトのラベルは、(複合)サブステートメントに含まれる最上位のステートメントに表示されますが、これは必須ではありません。宣言は、switchステートメントのサブステートメントに表示できます。 —エンドノート]