if constexpr와 컴파일 타임 분기
기존 방식의 문제
섹션 제목: “기존 방식의 문제”C++17 이전에는 타입에 따라 다른 코드를 실행하려면 SFINAE나 템플릿 특수화가 필요했습니다.
// SFINAE — 복잡하고 읽기 어려움template<typename T>auto serialize(T val) -> std::enable_if_t<std::is_integral_v<T>, std::string> { return std::to_string(val);}
template<typename T>auto serialize(T val) -> std::enable_if_t<std::is_floating_point_v<T>, std::string> { return std::to_string(val);}if constexpr 기본 사용
섹션 제목: “if constexpr 기본 사용”if constexpr는 조건을 컴파일 타임에 평가하고, 거짓인 분기의 코드를 인스턴스화하지 않습니다.
template<typename T>std::string serialize(T val) { if constexpr (std::is_integral_v<T>) { return std::to_string(val); } else if constexpr (std::is_floating_point_v<T>) { return std::to_string(val); } else { return val.to_string(); // T가 정수/실수가 아닐 때만 인스턴스화 }}일반 if와 달리, 선택되지 않은 분기 내의 코드는 문법 검사만 받고 컴파일되지 않습니다.
핵심 차이: 일반 if vs if constexpr
섹션 제목: “핵심 차이: 일반 if vs if constexpr”template<typename T>void print(T val) { if (std::is_integral_v<T>) { // T가 std::string일 때도 이 줄이 컴파일됨 → 오류 가능 std::cout << val * 2; }}
template<typename T>void print2(T val) { if constexpr (std::is_integral_v<T>) { std::cout << val * 2; // T가 integral이 아니면 무시됨 }}재귀 종료 조건에 활용
섹션 제목: “재귀 종료 조건에 활용”template<typename T, typename... Ts>void print_all(T first, Ts... rest) { std::cout << first << '\n'; if constexpr (sizeof...(rest) > 0) { print_all(rest...); // 0개일 때 인스턴스화 안 됨 } // C++17 이전: 재귀 종료용 특수화 함수가 별도 필요}
print_all(1, "hello", 3.14);타입 특성 기반 최적화
섹션 제목: “타입 특성 기반 최적화”template<typename Container>void clear(Container& c) { if constexpr (requires { c.clear(); }) { c.clear(); // clear() 있는 컨테이너 } else { c = Container{}; // 없으면 재할당 }}C++20 requires와 조합하면 더욱 강력합니다.
컴파일 타임 타입 디스패치
섹션 제목: “컴파일 타임 타입 디스패치”template<typename T>auto make_default() { if constexpr (std::is_same_v<T, std::string>) { return std::string{}; } else if constexpr (std::is_arithmetic_v<T>) { return T{0}; } else { static_assert(false, "지원하지 않는 타입"); }}static_assert(false, ...)를 사용할 때는 템플릿 파라미터에 의존하는 형태로 작성해야 합니다.
// 올바른 방식template<typename T>struct always_false : std::false_type {};
if constexpr (...) { ... }else { static_assert(always_false<T>::value, "지원하지 않는 타입"); }if constexpr는 선택되지 않은 분기를 인스턴스화하지 않으므로 템플릿 코드가 훨씬 간결해짐- SFINAE, 태그 디스패치, 템플릿 특수화 등의 복잡한 패턴을 대체 가능
- C++20
concepts와 함께 사용하면 제약 조건을 더 명확하게 표현 가능 - 런타임 조건에는 사용할 수 없으며, 조건식은 반드시
constexpr평가 가능해야 함