Оператор if
Условно выполняет другой оператор.
Используется там, где код нужно выполнить на основе условия выполненияили времени компиляции(с C++17) условия, или если оператор if оценивается в контексте явно константного вычисления(с C++23).
Синтаксис
атрибут (необязательно) if constexpr(необязательно) ( инициализирующий оператор (необязательно) условие ) оператор_true | (1) | |
атрибут (необязательно) if constexpr(необязательно) ( инициализирующий оператор (необязательно) условие ) оператор_true else оператор_false | (2) | |
атрибут (необязательно) if !(необязательно) consteval составной оператор | (3) | (с C++23) |
атрибут (необязательно) if !(необязательно) consteval составной оператор else оператор | (4) | (с C++23) |
| атрибут | - | (с C++11) любое количество атрибутов | ||
constexpr | - | (с C++17) если присутствует, оператор становится оператором constexpr if | ||
| инициализирующий оператор | - | (с C++17) либо
;, поэтому он часто описывается неформально как выражение или объявление, за которым следует точка с запятой. |
||
| условие | - | одно из
|
||
| оператор_true | - | любой оператор (часто составной оператор), который выполняется, если условие вычисляется как true |
||
| оператор_false | - | любой оператор (часто составной оператор), который выполняется, если условие вычисляется как false |
||
| составной оператор | - | любой составной оператор, который выполняется, если оператор if
|
||
| оператор | - | любой оператор (должен быть составным оператором, см. ниже), который выполняется, если оператор if
|
Описание
Если условие дает результат true после преобразования к типу bool, выполняется оператор_true.
Если часть else оператора if присутствует и условие дает результат false после преобразования к типу bool, выполняется оператор_false.
Второй форме оператора if (той, которая включает else), если оператор_true также является оператором if, то этот вложенный оператор if должен также содержать часть else (другими словами, во вложенных операторах if, else ассоциируется с ближайшим оператором if, у которого нет else).
#include <iostream>
int main()
{
// simple if-statement with an else clause
int i = 2;
if (i > 2)
std::cout << i << " is greater than 2\n";
else
std::cout << i << " is not greater than 2\n";
// nested if-statement
int j = 1;
if (i > 1)
if (j > 2)
std::cout << i << " > 1 and " << j << " > 2\n";
else // this else is part of if (j > 2), not of if (i > 1)
std::cout << i << " > 1 and " << j << " <= 2\n";
// declarations can be used as conditions with 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)) // cast fails, returns nullptr
p->df(); // not executed
if (auto p = dynamic_cast<Derived*>(bp2)) // cast succeeds
p->df(); // executed
}Вывод:
2 is not greater than 2 2 > 1 and 1 <= 2 df()
Операторы if с инициализаторомЕсли используется инициализирующий оператор, оператор if эквивалентен
или
за исключением того, что имена, объявленные инициализирующим оператором (если инициализирующий оператор является объявлением) и имена, объявленные условием (если условие является объявлением) находятся в одном объеме, который также является объемом обоих операторов. std::map<int, std::string> m;
std::mutex mx;
extern bool shared_flag; // guarded by 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 (const auto keywords = {"if", "for", "while"};
std::ranges::any_of(keywords, [&tok](const char* kw) { return tok == kw; }))
{
std::cerr << "Token must not be a keyword\n";
}
} | (с C++17) |
Constexpr ifУтверждение, которое начинается с В утверждении constexpr if значение condition должно быть контекстно преобразуемым константным выражением типа Если значение равно Операторы return в отброшенном операторе не участвуют в выводе типа возвращаемого значения функции: template<typename T>
auto get_value(T t)
{
if constexpr (std::is_pointer_v<T>)
return *t; // deduces return type to int for T = int*
else
return t; // deduces return type to int for T = int
}Отброшенный оператор может odr-использовать переменную, которая не определена: extern int x; // no definition of x required
int f()
{
if constexpr (true)
return 0;
else if (x)
return x;
else
return -x;
}За пределами шаблона отброшенный оператор полностью проверяется. void f()
{
if constexpr(false)
{
int i = 0;
int *p = i; // Error even though in discarded statement
}
}Если утверждение constexpr if появляется внутри шаблонизированного объекта, и если condition не является зависимым от значения после инстанцирования, отброшенный оператор не инстанцируется при инстанцировании окружающего шаблона. template<typename T, typename ... Rest>
void g(T&& p, Rest&& ...rs)
{
// ... handle p
if constexpr (sizeof...(rs) > 0)
g(rs...); // never instantiated with an empty argument list.
}Примечание: пример, где условие остается зависимым от значения после инстанцирования — это вложенный шаблон, например: template<class T>
void g()
{
auto lm = [=](auto p)
{
if constexpr (sizeof(T) == 1 && sizeof p == 1)
{
// this condition remains value-dependent after instantiation of g<T>,
// which affects implicit lambda captures
// this compound statement may be discarded only after
// instantiation of the lambda body
}
};
}Примечание: отброшенный оператор не может быть некорректным для любой возможной специализации: template<typename T>
void f()
{
if constexpr (std::is_arithmetic_v<T>)
// ...
else {
using invalid_array = int[-1]; // ill-formed: invalid for every T
static_assert(false, "Must be arithmetic"); // ill-formed before CWG2518
}
}Общие обходные пути до реализации CWG2518 для такого универсального оператора — это зависящее от типа выражение, которое всегда template<typename>
inline constexpr bool dependent_false_v = false;
template<typename T>
void f()
{
if constexpr (std::is_arithmetic_v<T>)
// ...
else {
// workaround before CWG2518
static_assert(dependent_false_v<T>, "Must be arithmetic");
}
}Метки (метки перехода, Примечание: объявление типа или объявление псевдонима(с C++23) можно использовать в качестве оператора инициализации утверждения constexpr if для уменьшения области действия псевдонима. | (с C++17) |
Consteval ifУтверждение, начинающееся с
и compound-statement, и statement (если таковое имеется) должны быть составными операторами. Если statement не является составным оператором, он по-прежнему будет обрабатываться как часть оператора consteval if (и, следовательно, приведет к ошибке компиляции): constexpr void f(bool b)
{
if (true)
if consteval {}
else ; // error: not a compound-statement
// else not associated with outer if
}Если утверждение consteval if оценивается в контексте явной оценки константного выражения, выполняется compound-statement. В противном случае, выполняется statement, если оно присутствует. Метка Если оператор начинается с
compound-statement в операторе consteval if (или statement в отрицательной форме) находится в непосредственном контексте функции, в котором вызов непосредственной функции не обязательно должен быть константным выражением. #include <cmath>
#include <cstdint>
#include <cstring>
#include <iostream>
constexpr bool is_constant_evaluated() noexcept
{
if consteval { return true; } else { return false; }
}
constexpr bool is_runtime_evaluated() noexcept
{
if not consteval { return true; } else { return false; }
}
consteval std::uint64_t ipow_ct(std::uint64_t base, std::uint8_t exp)
{
if (!base) return base;
std::uint64_t res{1};
while (exp)
{
if (exp & 1) res *= base;
exp /= 2;
base *= base;
}
return res;
}
constexpr std::uint64_t ipow(std::uint64_t base, std::uint8_t exp)
{
if consteval // use a compile-time friendly algorithm
{
return ipow_ct(base, exp);
}
else // use runtime evaluation
{
return std::pow(base, exp);
}
}
int main(int, const char* argv[])
{
static_assert(ipow(0,10) == 0 && ipow(2,10) == 1024);
std::cout << ipow(std::strlen(argv[0]), 3) << '\n';
} | (с C++23) |
Примечания
Если statement-true или statement-false не является составным оператором, он обрабатывается так, как будто он:
if (x)
int i;
// i is no longer in scopeэквивалентно
if (x)
{
int i;
}
// i is no longer in scopeОбласть действия имени, введенного condition, если это объявление, — это объединенная область действия обоих блоков операторов:
if (int x = f())
{
int x; // error: redeclaration of x
}
else
{
int x; // error: redeclaration of x
}Если statement-true выполняется с помощью goto или longjmp, condition не оценивается, и statement-false не выполняется.
| Встроенные преобразования не допускаются в condition оператора constexpr if, за исключением не-сужающих целочисленных преобразований в |
(с C++17) (до C++23) |
|
| (с C++17) |
| Макрос проверки функций | Значение | Std | Функция |
|---|---|---|---|
__cpp_if_constexpr | 201606L | (C++17) |
constexpr if |
__cpp_if_consteval | 202106L | (C++23) | consteval if |
Ключевые слова
if, else, constexpr, consteval
Отчеты о дефектах
Следующие поведенческие отчеты о дефектах были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применено к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| CWG 631 | C++98 | поток управления был неопределенным, если первая подвыражение достигнуто через метку | условие не оценивается, а второе подвыражение не выполняется (так же, как в C) |
См. также
|
(C++20) | определяет, происходит ли вызов в контексте вычисления константы (функция) |
Документация C для оператора if |
|
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/if