18. 템플릿 인스턴스화와 컴파일타임 디스패치(SFINAE·태그 디스패치·if constexpr)
난이도 최상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C++
// 주제: 템플릿 인스턴스화와 컴파일타임 디스패치 — SFINAE, 태그 디스패치, if constexpr.
//
// 오버로드 집합에서 어떤 후보가 "치환 실패(SFINAE)"로 조용히 빠지는지, 태그로 어떻게
// 컴파일타임에 분기하는지, if constexpr 가 런타임 if 와 무엇이 다른지를 다룬다.
//
// 과제:
// 1) 이 프로그램의 정확한 표준출력을 예측하라(다섯 줄 모두).
// 2) kind(42) 와 kind(3.14) 가 각각 어떤 오버로드로 가고, 다른 후보는 왜
// 후보 집합에서 제거되는지(SFINAE) 설명하라.
// 3) has_id<Player> 와 has_id<int> 가 각각 true/false 가 되는 원리(void_t 검출 관용구)를
// 설명하라.
// 4) describe() 의 태그 디스패치가 어떻게 컴파일타임에 obj/pod 로 갈리는지,
// 그리고 sizeInfo() 의 if constexpr 가 "버려지는 분기(discarded branch)"를
// 어떻게 처리하는지(런타임 if 와의 차이) 설명하라.
#include <cstdio>
#include <type_traits>
#include <utility>
// (2) 멤버 .id() 존재 검출 (void_t 관용구)
template <class T, class = void>
struct has_id : std::false_type {};
template <class T>
struct has_id<T, std::void_t<decltype(std::declval<T>().id())>> : std::true_type {};
// (1) enable_if 로 정수/부동소수 오버로드 분리
template <class T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
const char* kind(T) { return "integral"; }
template <class T, std::enable_if_t<std::is_floating_point<T>::value, int> = 0>
const char* kind(T) { return "floating"; }
// (3) 태그 디스패치
struct pod_tag {};
struct obj_tag {};
template <class T> const char* dispatch_impl(const T&, pod_tag) { return "pod"; }
template <class T> const char* dispatch_impl(const T&, obj_tag) { return "obj"; }
template <class T> const char* describe(const T& x) {
using tag = std::conditional_t<std::is_class<T>::value, obj_tag, pod_tag>;
return dispatch_impl(x, tag{});
}
// (4) if constexpr 컴파일타임 분기
template <class T> int sizeInfo(const T&) {
if constexpr (std::is_integral_v<T>) return (int)sizeof(T) * 10 + 1;
else if constexpr (std::is_floating_point_v<T>) return (int)sizeof(T) * 10 + 2;
else return -1;
}
struct Player { int id() const { return 7; } };
int main() {
std::printf("%s\n", kind(42));
std::printf("%s\n", kind(3.14));
std::printf("%d %d\n", (int)has_id<Player>::value, (int)has_id<int>::value);
std::printf("%s %s\n", describe(Player{}), describe(5));
std::printf("%d %d %d\n", sizeInfo(int{}), sizeInfo(double{}), sizeInfo(Player{}));
return 0;
} 내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.