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 が |
| 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...); // 空の引数リストで実体化されることはありません。
}
テンプレートの外側では、破棄された文は完全にチェックされます。 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言語リファレンス
|