# if statement

From cppreference.com
< cpp‎ | language

Conditionally executes another statement.

Used where code needs to be executed based on a run-time or compile-time condition.

### Syntax

attr(optional) `if` `(` condition `)` statement-true |  | (until C++17)
attr(optional) `if` `(` condition `)` statement-true `else` statement-false |  | (until C++17)
attr(optional) `if` `constexpr`(optional) `(` init-statement(optional) condition `)` statement-true |  | (since C++17)
attr(optional) `if` `constexpr`(optional) `(` init-statement(optional) condition `)` statement-true `else` statement-false |  | (since C++17)

attr(C++11) | - | any number of attributes

condition

-

one of

- expression which is contextually convertible to bool
- declaration of a single non-array variable with a brace-or-equals initializer.

init-statement(C++17)

-

either

- an expression statement (which may be a null statement "`;`")
- a simple declaration, typically a declaration of a variable with initializer, but it may declare arbitrary many variables or be a decomposition declaration

  Note that any init-statement must end with a semicolon `;`, which is why it is often described informally as an expression or a declaration followed by a semicolon.

statement-true | - | any statement (often a compound statement), which is executed if condition evaluates to true
statement-false | - | any statement (often a compound statement), which is executed if condition evaluates to false

### Explanation

If the condition yields true after conversion to bool, statement-true is executed.

If the else part of the if statement is present and condition yields false after conversion to bool, statement-false is executed.

In the second form of if statement (the one including else), if statement-true is also an if statement then that inner if statement must contain an else part as well (in other words, in nested if-statements, the else is associated with the closest if that doesn't have an else)

Run this code

    #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
    }

Output:

    2 is not greater than 2
    2 > 1 and 1 <= 2
    df()

#### If Statements with Initializer

If init-statement is used, the if statement is equivalent to

`{`

  init_statement
  `if` `constexpr`(optional) `(` condition `)`
    statement-true

`}`

or

`{`

  init_statement
  `if` `constexpr`(optional) `(` condition `)`
    statement-true
  `else`
    statement-false

`}`

Except that names declared by the init-statement (if init-statement is a declaration) and names declared by condition (if condition is a declaration) are in the same scope, which is also the scope of both statements.

    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 (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";
       }
    }

(since C++17)

#### Constexpr If

The statement that begins with `if constexpr` is known as the constexpr if statement.

In a constexpr if statement, the value of condition must be a contextually converted constant expression of type `bool`. If the value is `true`, then statement-false is discarded (if present), otherwise, statement-true is discarded.

The return statements in a discarded statement do not participate in function return type deduction:

    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
    }

The discarded statement can odr-use a variable that is not defined

    extern int x; // no definition of x required
    int f() {
    if constexpr (true)
        return 0;
    else if (x)
        return x;
    else
        return -x;
    }

If a constexpr if statement appears inside a templated entity, and if condition is not value-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 p
        if constexpr (sizeof...(rs) > 0)
            g(rs...); // never instantiated with an empty argument list.
    }

Outside a template, a discarded statement is fully checked. if constexpr is not a substitute for the `#if` preprocessing directive:

    void f() {
        if constexpr(false) {
            int i = 0;
            int *p = i; // Error even though in discarded statement
        }
    }

Note: an example where the condition remains value-dependent after instantiation is a nested template, e.g.

    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>
            }
        };
    }

Note: the discarded statement can't be ill-formed for every possible specialization:

    template <typename T>
    void f() {
         if constexpr (std::is_arithmetic_v<T>)
             // ...
         else
           static_assert(false, "Must be arithmetic"); // ill-formed: invalid for every T
    }

The common workaround for such a catch-all statement is a type-dependent expression that is always 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
    }

Labels (goto targets, `case` labels, and `default:`) appearing in a substatement of a constexpr if can only be referenced (by switch or goto) in the same substatement.

(since C++17)

### Notes

If statement_true or statement_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 by condition, 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
    }

If statement-true is entered by goto or longjmp, statement_false is not executed. | (since C++14)
Switch and goto are not allowed to jump into a branch of constexpr if statement. | (since C++17)

### Keywords

`if`, `else`, `constexpr`

### See Also

Retrieved from "https://en.cppreference.com/mwiki/index.php?title=cpp/language/if&oldid=109539"