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"
	);
}