Namespaces
Variants

if statement

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
if
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
constexpr (C++11)
consteval (C++20)
constinit (C++20)
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

조건부로 다른 문을 실행합니다.

조건에 따라 코드를 실행해야 하는 경우에 사용됨 , 또는 if 문이 명백하게 상수 평가되는 컨텍스트에서 평가되는지 여부 (C++23부터) .

목차

구문

attr  (선택 사항) if constexpr (선택 사항)
( init-statement  (선택 사항) condition ) statement-true
(1)
attr  (선택 사항) if constexpr (선택 사항)
( init-statement  (선택 사항) condition ) statement-true else statement-false
(2)
attr  (선택 사항) if ! (선택 사항) consteval compound-statement (3) (C++23부터)
attr  (선택 사항) if ! (선택 사항) consteval compound-statement else statement (4) (C++23부터)
1) if 구문에 else 분기가 없는 경우
2) if 구문과 else 분기
3) else 브랜치가 없는 consteval if 문
4) else 분기를 갖는 consteval if 문
attr - (C++11부터) 임의의 개수의 attributes
constexpr - (C++17부터) 존재할 경우, 해당 문은 constexpr if 문 이 됨
init-statement - (C++17부터) 다음 중 하나
(C++23부터)

모든 init-statement 는 세미콜론으로 끝나야 함. 이것이 흔히 비공식적으로 세미콜론 뒤에 오는 표현식이나 선언으로 설명되는 이유임.

condition - condition
statement-true - condition true 를 반환할 경우 실행될 statement
statement-false - condition false 를 반환할 경우 실행될 statement
compound-statement - if 문이 manifestly constant-evaluated context 에서 평가될 경우 실행될 compound statement (또는 ! consteval 앞에 올 경우 그러한 context에서 평가되지 않을 때)
statement - if 문이 manifestly constant-evaluated context에서 평가되지 않을 경우 실행될 statement (반드시 compound statement여야 함, 아래 참조 ) (또는 ! consteval 앞에 올 경우 그러한 context에서 평가될 때)

조건

조건은 condition expression 이거나 simple declaration 일 수 있습니다.

  • 구문적으로 structured binding 선언으로 해결될 수 있는 경우, 이는 structured binding 선언으로 해석됩니다.
(since C++26)
  • 만약 문법적으로 표현식으로 해결될 수 있다면, 표현식으로 취급됩니다. 그렇지 않으면 선언으로 취급됩니다 (이는 구조적 바인딩 선언이 아닌 선언임) (C++26부터) .

제어가 조건에 도달하면, 조건은 값을 산출하며, 이 값은 제어가 어느 분기로 이동할지 결정하는 데 사용됩니다.

표현식

만약 condition 이 표현식인 경우, 생성되는 값은 해당 표현식이 bool 으로 문맥상 변환된 값입니다. 해당 변환이 잘못된 경우, 프로그램은 잘못된 형식입니다.

선언

만약 condition 이 단순 선언인 경우, 반환되는 값은 결정 변수의 값(아래 참조)이 bool 으로 문맥상 변환된 값입니다. 해당 변환이 잘못된 경우, 프로그램은 잘못된 형식입니다.

비구조적 바인딩 선언

선언에는 다음과 같은 제한 사항이 있습니다:

  • 구문적으로 다음 형식을 따릅니다:
  • type-specifier-seq declarator = assignment-expression
(C++11 이전)
  • attribute-specifier-seq (선택 사항) decl-specifier-seq declarator brace-or-equal-initializer
(C++11 이후)

선언의 결정 변수는 선언된 변수입니다.

구조화된 바인딩 선언

선언에는 다음과 같은 제한 사항이 있습니다:

선언의 결정 변수는 선언에 의해 도입된 e 라는 발명된 변수입니다.

(C++26부터)

브랜치 선택

만약 condition true 를 반환하면, statement-true 가 실행됩니다.

만약 else 부분이 존재하고 condition false 를 반환하면, statement-false 가 실행됩니다.

만약 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
attr  (optional) if constexpr (optional) ( condition )
statement-true

}

또는

{
init-statement
attr  (optional) if constexpr (optional) ( condition )
statement-true
else
statement-false

}

단, init-statement 에 의해 선언된 이름들( init-statement 가 선언인 경우)과 condition 에 의해 선언된 이름들( condition 가 선언인 경우)은 동일한 스코프에 있으며, 이 스코프는 두 statement 들의 스코프이기도 합니다.

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

if constexpr 로 시작하는 구문은 constexpr if 문 으로 알려져 있습니다. constexpr if 문의 모든 하위 구문은 제어 흐름 제한 구문 입니다.

constexpr if 문에서, 조건 bool 타입으로 문맥적으로 변환된 상수 표현식 bool 이어야 합니다 (C++23 이전) bool로 문맥적으로 변환되는 bool 표현식이어야 하며, 이 변환은 상수 표현식 이어야 합니다 (C++23 이후) .

만약 condition true 를 반환하면, statement-false 는 (존재하는 경우) 무시되며, 그렇지 않으면 statement-true 가 무시됩니다.

폐기된 문장 내의 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-use 할 수 있습니다:

extern int x; // x의 정의는 필요하지 않음
int f()
{
    if constexpr (true)
        return 0;
    else if (x)
        return x;
    else
        return -x;
}

템플릿 외부에서는 폐기된 구문이 완전히 검사됩니다. if constexpr #if 전처리기 지시문의 대체제가 아닙니다:

void f()
{
    if constexpr(false)
    {
        int i = 0;
        int *p = i; // 오류: 폐기된 문장 내부에서도 발생
    }
}

constexpr if 문이 템플릿 엔티티 내부에 나타나고, 인스턴스화 후 조건 값-의존적 이 아닌 경우, 버려진 문은 둘러싼 템플릿이 인스턴스화될 때 인스턴스화되지 않습니다.

template<typename T, typename ... Rest>
void g(T&& p, Rest&& ...rs)
{
    // ... p 처리
    if constexpr (sizeof...(rs) > 0)
        g(rs...); // 빈 인수 목록으로는 절대 인스턴스화되지 않음
}

조건이 인스턴스화 후에도 값에 의존하는 상태로 남는 것은 중첩 템플릿입니다:

template<class T>
void g()
{
    auto lm = [=](auto p)
    {
        if constexpr (sizeof(T) == 1 && sizeof p == 1)
        {
            // 이 조건은 g<T>의 인스턴스화 이후에도 값 의존성을 유지하며,
            // 이는 암시적 람다 캡처에 영향을 미침
            // 이 복합문은 람다 본문의 인스턴스화 이후에만
            // 폐기될 수 있음
        }
    };
}

폐기된 문장은 가능한 모든 특수화에 대해 잘못 형성될 수 없습니다:

template<typename T>
void f()
{
    if constexpr (std::is_arithmetic_v<T>)
        // ...
    else {
        using invalid_array = int[-1]; // 잘못된 형식: 모든 T에 대해 유효하지 않음
        static_assert(false, "Must be arithmetic"); // CWG2518 이전에는 잘못된 형식
    }
}

CWG issue 2518 이 구현되기 전에 이러한 catch-all 문에 대한 일반적인 해결 방법은 항상 false 인 타입 종속적 표현식입니다:

template<typename>
constexpr bool dependent_false_v = false;
template<typename T>
void f()
{
    if constexpr (std::is_arithmetic_v<T>)
        // ...
    else {
        // CWG2518 이전의 해결 방법
        static_assert(dependent_false_v<T>, "Must be arithmetic");
    }
}

typedef 선언 또는 alias 선언 (C++23부터) 은 constexpr if 문의 init-statement 로 사용되어 타입 별칭의 범위를 축소하는 데 사용될 수 있습니다.

(C++17 이후)


Consteval if

if consteval 로 시작하는 구문은 consteval if 문 으로 알려져 있습니다. consteval if 문의 모든 하위 구문은 제어 흐름 제한 구문 입니다.

statement 는 복합 문이어야 하며, 복합 문이 아닌 경우에도(따라서 컴파일 오류가 발생함) 여전히 consteval if 문의 일부로 처리됩니다:

constexpr void f(bool b)
{
    if (true)
        if consteval {}
        else ; // 오류: 복합문이 아님
               // else가 바깥쪽 if와 연결되지 않음
}

consteval if 문이 명백하게 상수 평가되는 컨텍스트 에서 평가되면, compound-statement 가 실행됩니다. 그렇지 않으면, statement 가 존재할 경우 해당 문이 실행됩니다.

만약 구문이 if ! consteval 로 시작하는 경우, compound-statement statement (존재하는 경우)는 모두 복합 구문이어야 합니다. 이러한 구문은 consteval if 구문으로 간주되지 않지만, consteval if 구문과 동등합니다:

  • if ! consteval { /* stmt */ } 는 다음과 동등합니다
if consteval { } else { /* stmt */ } .
  • if ! consteval { /* stmt-1 */ } else { /* stmt-2 */ } 는 다음 코드와 동일합니다
if consteval { /* stmt-2 */ } else { /* stmt-1 */ } .

compound-statement 은 consteval if 문에서 (또는 부정 형태의 statement 에서) immediate function context 에 위치하며, 이 컨텍스트에서는 immediate function에 대한 호출이 상수 표현식일 필요가 없습니다.

#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 // 컴파일 타임 친화적인 알고리즘 사용
    {
        return ipow_ct(base, exp);
    }
    else // 런타임 평가 사용
    {
        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는 더 이상 스코프 내에 있지 않음

와 동일합니다

if (x)
{
    int i;
}
// i는 더 이상 스코프 내에 있지 않음

condition 에 의해 도입된 이름의 범위는, 만약 그것이 선언이라면, 두 문장의 본문 모두의 결합된 범위입니다:

if (int x = f())
{
    int x; // 오류: x의 재선언
}
else
{
    int x; // 오류: x의 재선언
}

만약 statement-true goto 또는 longjmp 에 의해 진입되면, condition 은 평가되지 않고 statement-false 는 실행되지 않습니다.

constexpr if 문의 조건 에서는 내장 변환은 허용되지 않습니다. 단, 축소 변환 이 아닌 정수 계열 변환 bool 로 변환하는 경우는 예외입니다.

(C++17부터)
(C++23 이전까지)
기능 테스트 매크로 표준 기능
__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 문서 for if