if
statementGeneral topics | ||||||||||||||||
Flow control | ||||||||||||||||
Conditional execution statements | ||||||||||||||||
| ||||||||||||||||
Iteration statements (loops) | ||||||||||||||||
Jump statements | ||||||||||||||||
Functions | ||||||||||||||||
Function declaration | ||||||||||||||||
Lambda function expression | ||||||||||||||||
inline specifier | ||||||||||||||||
Dynamic exception specifications(until C++17*) | ||||||||||||||||
noexcept specifier(C++11) | ||||||||||||||||
Exceptions | ||||||||||||||||
Namespaces | ||||||||||||||||
Types | ||||||||||||||||
Specifiers | ||||||||||||||||
| ||||||||||||||||
Storage duration specifiers | ||||||||||||||||
Initialization | ||||||||||||||||
Expressions | ||||||||||||||||
Alternative representations | ||||||||||||||||
Literals | ||||||||||||||||
Boolean -Integer -Floating-point | ||||||||||||||||
Character -String -nullptr(C++11) | ||||||||||||||||
User-defined(C++11) | ||||||||||||||||
Utilities | ||||||||||||||||
Attributes(C++11) | ||||||||||||||||
Types | ||||||||||||||||
typedef declaration | ||||||||||||||||
Type alias declaration(C++11) | ||||||||||||||||
Casts | ||||||||||||||||
Memory allocation | ||||||||||||||||
Classes | ||||||||||||||||
Class-specific function properties | ||||||||||||||||
| ||||||||||||||||
Special member functions | ||||||||||||||||
Templates | ||||||||||||||||
Miscellaneous | ||||||||||||||||
Conditionally executes another statement.
Used where code needs to be executed based on a condition, or whether theif statement is evaluated in a manifestly constant-evaluated context(since C++23).
Contents |
attr (optional)if constexpr (optional)( init-statement (optional)condition) statement-true | (1) | ||||||||
attr (optional)if constexpr (optional)( init-statement (optional)condition) statement-trueelse statement-false | (2) | ||||||||
attr (optional)if ! (optional)consteval compound-statement | (3) | (since C++23) | |||||||
attr (optional)if ! (optional)consteval compound-statementelse statement | (4) | (since C++23) | |||||||
attr | - | (since C++11) any number ofattributes | ||
constexpr | - | (since C++17) if present, the statement becomes aconstexpr if statement | ||
init-statement | - | (since C++17) either
Note that anyinit-statement must end with a semicolon. This is why it is often described informally as an expression or a declaration followed by a semicolon. | ||
condition | - | acondition | ||
statement-true | - | thestatement to be executed ifcondition yieldstrue | ||
statement-false | - | the statement to be executed ifcondition yieldsfalse | ||
compound-statement | - | thecompound statement to be executed if theif statement is evaluated in amanifestly constant-evaluated context (or is not evaluated in such a context if! is precedingconsteval) | ||
statement | - | the statement (must be a compound statement, seebelow) to be executed if theif statement is not evaluated in a manifestly constant-evaluated context (or is evaluated in such a context if! is precedingconsteval) |
Acondition can either be anexpression or asimple declaration.
| (since C++26) |
When control reaches condition, the condition will yield a value, which is used to determine which branch the control will go to.
Ifcondition is an expression, the value it yields is the the value of the expression contextually converted tobool. If that conversion is ill-formed, the program is ill-formed.
Ifcondition is a simple declaration, the value it yields is the value of the decision variable (see below) contextually converted tobool. If that conversion is ill-formed, the program is ill-formed.
The declaration has the following restrictions:
| (until C++11) |
| (since C++11) |
The decision variable of the declaration is the declared variable.
Structured binding declarationThe declaration has the following restrictions:
The decision variable of the declaration is the invented variableeintroduced by the declaration. | (since C++26) |
If thecondition yieldstrue,statement-true is executed.
If theelse part of theif statement is present andcondition yieldsfalse,statement-false is executed.
If theelse part of theif statement is present andstatement-true is also anif statement, then that innerif statement must contain anelse part as well (in other words, in nestedif statements, theelse is associated with the closestif that does not yet have an associatedelse).
#include <iostream> int main(){// simple if-statement with an else clauseint i=2;if(i>2)std::cout<< i<<" is greater than 2\n";elsestd::cout<< i<<" is not greater than 2\n"; // nested if-statementint 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_caststruct 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}
Output:
2 is not greater than 22 > 1 and 1 <= 2df()
if statements with initializerIfinit-statement is used, theif statement is equivalent to
or
Except that names declared by theinit-statement (ifinit-statement is a declaration) and names declared bycondition (ifcondition is a declaration) are in the same scope, which is also the scope of bothstatement s. std::map<int,std::string> m;std::mutex mx;externbool 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(constauto keywords={"if","for","while"}; std::ranges::any_of(keywords,[&tok](constchar* kw){return tok== kw;})){std::cerr<<"Token must not be a keyword\n";}} | (since C++17) |
Constexpr ifThe statement that begins withifconstexpr is known as theconstexpr if statement. All substatements of a constexpr if statement arecontrol-flow-limited statements. In a constexpr if statement,condition must beacontextually converted constant expression of typebool(until C++23)an expressioncontextually converted tobool, where the conversion is aconstant expression(since C++23). Ifcondition yieldstrue, thenstatement-false is discarded (if present), otherwise,statement-true is discarded. Thereturn statements in a discarded statement do not participate in function return type deduction: template<typename T>auto get_value(T t){ifconstexpr(std::is_pointer_v<T>)return*t;// deduces return type to int for T = int*elsereturn t;// deduces return type to int for T = int} The discarded statement canODR-use a variable that is not defined: externint x;// no definition of x required int f(){ifconstexpr(true)return0;elseif(x)return x;elsereturn-x;} Outside a template, a discarded statement is fully checked.ifconstexpr is not a substitute for the#if preprocessing directive: void f(){ifconstexpr(false){int i=0;int*p= i;// Error even though in discarded statement}} If a constexpr if statement appears inside atemplated entity, and ifcondition is notvalue-dependent after instantiation, the discarded statement is not instantiated when the enclosing template is instantiated. template<typename T,typename ...Rest>void g(T&& p, Rest&& ...rs){// ... handle pifconstexpr(sizeof...(rs)>0) g(rs...);// never instantiated with an empty argument list} The condition remains value-dependent after instantiation is a nested template: template<class T>void g(){auto lm=[=](auto p){ifconstexpr(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}};} The discarded statement cannot be ill-formed for every possible specialization: template<typename T>void f(){ifconstexpr(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}} The common workaround before the implementation ofCWG issue 2518 for such a catch-all statement is a type-dependent expression that is alwaysfalse: template<typename>constexprbool dependent_false_v=false; template<typename T>void f(){ifconstexpr(std::is_arithmetic_v<T>)// ...else{// workaround before CWG2518 static_assert(dependent_false_v<T>,"Must be arithmetic");}} Atypedef declarationoralias declaration(since C++23) can be used as theinit-statement of a constexpr if statement to reduce the scope of the type alias.
| (since C++17) |
Consteval ifThe statement that begins withif consteval is known as theconsteval if statement. All substatements of a consteval if statement arecontrol-flow-limited statements. statement must be a compound statement, and it will still be treated as a part of the consteval if statement even if it is not a compound statement (and thus results in a compilation error): Run this code constexprvoid f(bool b){if(true)if consteval{}else;// error: not a compound-statement// else not associated with outer if} If a consteval if statement is evaluated in amanifestly constant-evaluated context,compound-statement is executed. Otherwise,statement is executed if it is present. If the statement begins withif!consteval, thecompound-statement andstatement (if any) must both be compound statements. Such statements are not considered consteval if statements, but are equivalent to consteval if statements:
compound-statement in a consteval if statement (orstatement in the negative form) is in animmediate function context, in which a call to an immediate function needs not to be a constant expression. Run this code #include <cmath>#include <cstdint>#include <cstring>#include <iostream> constexprbool is_constant_evaluated()noexcept{if consteval{returntrue;}else{returnfalse;}} constexprbool is_runtime_evaluated()noexcept{if not consteval{returntrue;}else{returnfalse;}} constevalstd::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;} constexprstd::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{returnstd::pow(base, exp);}} int main(int,constchar* argv[]){ static_assert(ipow(0,10)==0&& ipow(2,10)==1024);std::cout<< ipow(std::strlen(argv[0]),3)<<'\n';} | (since C++23) |
Ifstatement-true orstatement-false is not a compound statement, it is treated as if it were:
if(x)int i;// i is no longer in scope
is the same as
if(x){int i;}// i is no longer in scope
The scope of the name introduced bycondition, if it is a declaration, is the combined scope of both statements' bodies:
if(int x= f()){int x;// error: redeclaration of x}else{int x;// error: redeclaration of x}
Ifstatement-true is entered bygoto
orlongjmp,condition is not evaluated andstatement-false is not executed.
Built-in conversions are not allowed in thecondition of a constexpr if statement, except for non-narrowingintegral conversions tobool. | (since C++17) (until C++23) |
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_if_constexpr | 201606L | (C++17) | constexprif |
__cpp_if_consteval | 202106L | (C++23) | constevalif |
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 631 | C++98 | the control flow was unspecified if the first substatement is reached via a label | the condition is not evaluated and the second substatement is not executed (same as in C) |
(C++20) | detects whether the call occurs within a constant-evaluated context (function)[edit] |
C documentation forif statement |