C++ - 템플릿 자동추론으로 타입별 로직 처리하기
함수 중 매개변수 타입에 따라 별도의 로직을 처리해야하는 함수가 있었다
parse(type);
type 인자가 무엇이 들어오냐에 따라 로직이 달라야했다.
필수로 컴파일 단계에서 타입이 결정되기를 바랬다.
C++17
std 라이브러리에서 타입 비교로 is_same_v 기능과 컴파일 시간에 강제로 타입을 추론하도록 constexpr 상수 키워드를 사용하였다.
#include <type_traits>
#if __cplusplus >= 201703L
template<typename T>
inline void parse(T& out) {
if constexpr (std::is_same_v<T, std::string>) {
// 문자열 처리
}
else if constexpr (std::is_same_v<T, bool>) {
// 불리언 처리
}
else if constexpr (std::is_integral_v<T>) {
// 정수형 처리
}
else if constexpr (std::is_floating_point_v<T>) {
// 실수형 처리
}
else {
// 타입 추론이 실패한 경우 오류 내보내기
static_assert(std::is_same_v<T, void>, "Unsupported argument type");
}
}
#elif
constexpr 키워드로 너무 많은 로직이 있는 경우 컴파일이 길어질 수 있다.
C++14
17에서 사용한 constexpr 상수를 사용 못할 경우 컴파일에 타입을 추론하는 다른 함수로 사용이 필요하다.
std 라이브러리에서 템플릿 특수화, 함수 오버로딩 지원하는 std::enable_if 기능을 활용할 수 있다.
#include <type_traits>
#if __cplusplus >= 201703L
// 문자열 반환
template<typename T>
typename std::enable_if<std::is_same<T, std::string>::value>::type
parse(T& out) {
// 문자열 로직 처리
}
// 불리언 반환
template<typename T>
typename std::enable_if<std::is_same<T, bool>::value>::type
parse(T& out) {
// 불리언 로직 처리
}
// 정수 반환
template<typename T>
typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value>::type
parse(T& out) {
// 정수형 로직 처리
}
// 실수 반환
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value>::type
parse(T& out) {
// 실수형 로직 처리
}
#endif
참고로 SFINAE 기능으로 타입 추론 실패로 인한 오류가 없으므로 주의한다.
컴파일 단계에서 올바르게 동작하는지 아래와 같이 테스트 코드용 함수를 만들어 검증한다.
template<typename T>
void parseAssert(T& out) {
static_assert(
std::is_same<T, std::string>:value ||
std::is_same<T, bool>::value ||
std::in_integral<T>::value ||
std::is_floating_point<T>::value,
"[DEBUG] Failed!! Unsupported type for parse"
);
}