if 文
別の文を条件付きで実行します。
実行時またはコンパイル時の条件に基づいてコードを実行する必要があるときに使用されます。
目次 |
[編集] 構文
attr(オプション) if ( condition ) statement-true
|
(C++17未満) | ||||||||
attr(オプション) if ( condition ) statement-true else statement-false
|
(C++17未満) | ||||||||
attr(オプション) if constexpr (オプション) ( init-statement(オプション) condition ) statement-true
|
(C++17以上) | ||||||||
attr(オプション) if constexpr (オプション) ( init-statement(オプション) condition ) statement-true else 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; extern bool 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](const char* 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) { if constexpr (std::is_pointer_v<T>) return *t; // T = int* の場合、戻り値の型は int に推定されます。 else return t; // T = int の場合、戻り値の型は int に推定されます。 } 破棄された文は定義されていない変数を ODR 使用できます。 extern int x; // x の定義は要求されません。 int f() { if constexpr (true) return 0; else if (x) return x; else return -x; } constexpr if 文がテンプレート化されたエンティティの内部に現れた場合、かつ、 condition が実体化後に値依存でない場合、囲っているテンプレートが実体化されたとき、破棄された式は実体化されません。 template<typename T, typename ... Rest> void g(T&& p, Rest&& ...rs) { // p を使って何か処理する if constexpr (sizeof...(rs) > 0) g(rs...); // 空の引数リストで実体化されることはありません。 } テンプレートの外側では、破棄された文は完全にチェックされます。 if constexpr は #if プリプロセッサ指令の置き換えではありません。 void f() { if constexpr(false) { int i = 0; int *p = i; // 破棄された文内であってもエラー } }
template<class T> void g() { auto lm = [](auto p) { if constexpr (sizeof(T) == 1 && sizeof p == 1) { // この条件式は g<T> の実体化後も値依存が残ります。 } }; } ノート: 破棄された文は、すべての有り得る特殊化について ill-formed であってはなりません。 template <typename T> void f() { if constexpr (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() { if constexpr (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言語リファレンス
|