if 文
別の文を条件付きで実行します。
実行時またはコンパイル時の条件に基づいてコードを実行する必要があるときに使用されます。
目次 |
[編集]構文
attr(オプション)if ( condition) statement-true | (C++17未満) | ||||||||
attr(オプション)if ( condition) statement-trueelse statement-false | (C++17未満) | ||||||||
attr(オプション)if constexpr (オプション)( init-statement(オプション)condition) statement-true | (C++17以上) | ||||||||
attr(オプション)if constexpr (オプション)( init-statement(オプション)condition) statement-trueelse statement-false | (C++17以上) | ||||||||
attr(C++11) | - | 任意個の属性。 |
condition | - | 以下のいずれか。 |
init-statement(C++17) | - | 以下のいずれか。
|
statement-true | - | 任意の文 (複文であることが多い)。 condition が true に評価された場合に実行されます。 |
statement-false | - | 任意の文 (複文であることが多い)。 condition が false に評価された場合に実行されます。 |
[編集]説明
condition が bool への変換後に true を生成した場合は、 statement-true が実行されます。
if 文の else 部が存在し、 condition が bool への変換後に false を生成した場合は、 statement-false が実行されます。
if 文の2つめの形式 (else を含む形式) において、 statement-true もまた if 文の場合は、その内側の if 文も同様に else 部を含まなければなりません (別の言い方をすると、ネストした if 文において、 else は else を持たない最も近い if に紐付けられます)。
#include <iostream> int main(){// else 節付きの単純な if 文int i =2;if(i >2){std::cout<< i <<" is greater than 2\n";}else{std::cout<< i <<" is not greater than 2\n";} // ネストした if 文int j =1;if(i >1)if(j >2)std::cout<< i <<" > 1 and "<< j <<" > 2\n";else// この else は if (i > 1) のではなく if (j > 2) の一部です。std::cout<< i <<" > 1 and "<< j <<" <= 2\n"; // 宣言を dynamic_cast を伴った条件式として使用できます。struct Base {virtual ~Base(){}};struct Derived : Base {void df(){std::cout<<"df()\n";}}; Base* bp1 = new Base; Base* bp2 = new Derived; if(Derived* p =dynamic_cast<Derived*>(bp1))// キャストは失敗し、 nullptr を返します。 p->df();// 実行されません。 if(auto p =dynamic_cast<Derived*>(bp2))// キャストは成功します。 p->df();// 実行されます。}
出力:
2 is not greater than 2 2 > 1 and 1 <= 2 df()
初期化子付きの if 文init-statement が使用される場合、その if 文は以下と同等です。
または
ただし、 init-statement によって宣言された名前 (init-statement が宣言の場合) および condition によって宣言された名前 (condition が宣言の場合) は同じスコープであり、それは両方の statement のスコープでもあります。 std::map<int, std::string> m;std::mutex mx;externbool shared_flag;// mx によって保護されるint demo(){if(auto it = m.find(10); it != m.end()){return it->second.size();}if(char buf[10];std::fgets(buf, 10, stdin)){ m[0]+= buf;}if(std::lock_guard lock(mx); shared_flag){ unsafe_ping(); shared_flag =false;}if(int s;int count = ReadBytesWithSignal(&s)){ publish(count); raise(s);}if(auto keywords ={"if", "for", "while"};std::any_of(keywords.begin(), keywords.end(), [&s](constchar* kw){return s == kw;})){std::cerr<<"Token must not be a keyword\n";}} | (C++17以上) |
constexpr if
constexpr if 文では、 破棄される文内の return 文は、関数の戻り値の型の推定に寄与しません。 template<typename T>auto get_value(T t){ifconstexpr(std::is_pointer_v<T>)return*t;// T = int* の場合、戻り値の型は int に推定されます。elsereturn t;// T = int の場合、戻り値の型は int に推定されます。} 破棄された文は定義されていない変数を ODR 使用できます。 externint x;// x の定義は要求されません。int f(){ifconstexpr(true)return0;elseif(x)return x;elsereturn-x;} constexpr if 文がテンプレート化されたエンティティの内部に現れた場合、かつ、 condition が実体化後に値依存でない場合、囲っているテンプレートが実体化されたとき、破棄された式は実体化されません。 template<typename T, typename ... Rest>void g(T&& p, Rest&& ...rs){// p を使って何か処理するifconstexpr(sizeof...(rs)>0) g(rs...);// 空の引数リストで実体化されることはありません。} テンプレートの外側では、破棄された文は完全にチェックされます。 ifconstexpr は #if プリプロセッサ指令の置き換えではありません。 void f(){ifconstexpr(false){int i =0;int*p = i;// 破棄された文内であってもエラー}}
template<class T>void g(){auto lm =[](auto p){ifconstexpr(sizeof(T)==1&& sizeof p ==1){// この条件式は g<T> の実体化後も値依存が残ります。}};} ノート: 破棄された文は、すべての有り得る特殊化について ill-formed であってはなりません。 template<typename T>void f(){ifconstexpr(std::is_arithmetic_v<T>)// ...else static_assert(false, "Must be arithmetic");// ill-formed、すべての T について無効} そのような全キャッチ文に対するワークアラウンドは、常に false になる型依存の式です。 template<class T>struct dependent_false :std::false_type{};template<typename T>void f(){ifconstexpr(std::is_arithmetic_v<T>)// ...else static_assert(dependent_false<T>::value, "Must be arithmetic");// OK} constexpr if の部分文内に現れるラベル (goto の飛び先、 | (C++17以上) |
[編集]ノート
statement-true または statement-false が複文でない場合は、以下のように扱われます。
if(x)int i;// この時点で i はスコープ外です。
これは以下と同じです。
if(x){int i;}// この時点で i はスコープ外です。
condition によって導入された名前 (それが宣言であった場合) のスコープは、両方の文の本体の合成されたスコープです。
if(int x = f()){int x;// エラー、 x の再宣言。}else{int x;// エラー、 x の再宣言。}
statement-true が goto または longjmp によって入られた場合、 statement-false は実行されません。 | (C++14以上) |
switch および goto が constexpr if 文の分岐内にジャンプすることは許されません。 | (C++17以上) |
[編集]キーワード
[編集]関連項目
if 文 の C言語リファレンス |