if
statement
조건부로 다른 문을 실행합니다.
조건에 따라 코드를 실행해야 하는 경우에 사용됨 , 또는 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부터) | |||||||
| attr | - | (C++11부터) 임의의 개수의 attributes | ||
constexpr
|
- | (C++17부터) 존재할 경우, 해당 문은 constexpr if 문 이 됨 | ||
| init-statement | - |
(C++17부터)
다음 중 하나
모든 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 일 수 있습니다.
|
(since C++26) |
- 만약 문법적으로 표현식으로 해결될 수 있다면, 표현식으로 취급됩니다. 그렇지 않으면 선언으로 취급됩니다 (이는 구조적 바인딩 선언이 아닌 선언임) (C++26부터) .
제어가 조건에 도달하면, 조건은 값을 산출하며, 이 값은 제어가 어느 분기로 이동할지 결정하는 데 사용됩니다.
표현식
만약 condition 이 표현식인 경우, 생성되는 값은 해당 표현식이 bool 으로 문맥상 변환된 값입니다. 해당 변환이 잘못된 경우, 프로그램은 잘못된 형식입니다.
선언
만약 condition 이 단순 선언인 경우, 반환되는 값은 결정 변수의 값(아래 참조)이 bool 으로 문맥상 변환된 값입니다. 해당 변환이 잘못된 경우, 프로그램은 잘못된 형식입니다.
비구조적 바인딩 선언
선언에는 다음과 같은 제한 사항이 있습니다:
- 구문적으로 다음 형식을 따릅니다:
|
(C++11 이전) |
|
(C++11 이후) |
- 선언자는 함수 나 배열 을 지정할 수 없습니다.
- 타입 지정자 시퀀스 (C++11 이전) 선언 지정자 시퀀스 는 타입 지정자와 constexpr 만 포함할 수 있으며, (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 에 의해 선언된 이름들( 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 ifif 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 ifif 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 구문과 동등합니다:
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++20)
|
호출이 상수 평가 컨텍스트 내에서 발생하는지 감지
(함수) |
|
C 문서
for
if
문
|
|