C++에는 런타임 타입 정보(RTTI)를 알려주는 typeid 시스템이 들어가 있습니다. 따라서 컴파일 언어이면서도 생각보다는 유연하게 실행 시간에 특정 변수의 타입을 조회하고 타입 간의 연산을 수행할 수가 있습니다. typeid로 얻어지는 type_info 인스턴스는 name()이라는 멤버 함수를 가지는데, 이 멤버 함수는 해당 타입의 이름을 알려줍니다. 이 값을 통해 현재 변수의 타입이 무엇인지 유저에게 문자열로 출력해줄 수가 있는 것이죠.
문제는 이 name()이 사실 사람이 읽기에 적합한 문자열을 주지 않는다는 것입니다. (게다가 컴파일 환경에 따라 출력값이 달라질 수도 있구요.) 예로 gcc 8.3에서 typeid(std::vector<size_t>).name()는 St6vectorImSaImEE라는 값을 반환합니다. 보시다시피 mangling이 되어서 알아보기도 어렵고 표준화가 되어 있지 않아 어떤 값이 나올지를 예측하기 어렵습니다.
이를 해결하기 위해 gcc에서만 지원하는 demangle함수(https://stackoverflow.com/questions/281818/unmangling-the-result-of-stdtype-infoname)를 사용할 수도 있고, boost::typeindex의 pretty_name이라는 함수(https://stackoverflow.com/questions/33386672/boostcoredemangle-on-visual-studio-typeid-name)를 쓸 수도 있습니다.
타입 이름을 프로그래머가 컨트롤할 수 있는 범위 내에서 컴파일 타임에 얻고 싶다면, 위의 두 옵션을 사용하지 않고 직접 타입의 이름을 구하는 템플릿 함수를 작성할 수도 있습니다. 구현해야할게 조금 많지만, 컴파일러를 타지 않으며 프로그래머가 통제할 수 있는 방법이라고 할 수 있죠. 서론은 그만 끊고 바로 코드로 들어가보도록 하겠습니다.
우리는 위와 같은 readable_name이라는 템플릿 함수를 구현해볼 겁니다. 템플릿 인자로 타입을 넣으면 그 타입의 이름을 std::string으로 되돌려 주는 함수죠. 먼저 가장 쉬운 기본 타입들을 구현해봅시다.
readable_name_impl이라는 함수를 오버로딩하고 있는것을 주목해보세요. 파라미터로는 해당 타입의 포인터를 받고 있습니다. 이렇게 한 이유는 해당 타입의 null 포인터를 하나 만들어서 파라미터로 넘기면 컴파일러가 알아서 타입이 맞는 함수를 선택하여 호출해주기 때문입니다. 포인터가 아니라 그냥 타입 그 자체를 파라미터로 받아도 되겠지만, 그 경우 생성자가 없거나 금지된 타입의 경우 문제가 발생할 수 있죠. 이제 기본 타입을 조합하여 복합 타입들의 이름을 생성하는 함수를 구현해봅시다.
엄청 간단합니다. 컨테이너의 파라미터를 템플릿 파라미터로 가지는 readable_name_impl 함수들을 구현했습니다. 템플릿 내부의 타입들은 다시 readable_name을 호출함으로써 재귀적으로 타입명을 생성합니다. 이로써 std::map<std::vector<size_t>, std::pair<size_t, double>>과 같이 복잡한 타입들도 컴파일러가 알아서 위 함수들을 재귀적으로 호출해서 해결할 수 있게 됩니다!
그리고 최종적으로 readable_name 함수의 구현은 위와 같습니다. 그냥 nullptr를 _Type*로 캐스팅해서 readable_name_impl에 던져준게 전부입니다. 그러면 이제 다음과 같은게 가능해지는것이죠.
템플릿 가지고 놀기 참 쉽죠~?
[C++ 11] 문자가 특정 문자 집합에 속하는지 우아하게 테스트하기 (0) | 2020.03.30 |
---|---|
[C++] 빠른 generate_canonical 함수 만들기 (8) | 2019.12.25 |
[C++, Eigen] Eigen cast함수 SIMD로 벡터화하기 (1) | 2019.10.13 |
[c++] CRTP를 이용한 다단계 정적 상속으로 코드 최적화하기 (6) | 2019.03.07 |
[C++] 템플릿 함수를 이용해 STL 컨테이너를 직렬화해보자 (1) | 2018.10.05 |
[c++] 템플릿 메타 프로그래밍으로 르장드르 다항식 계산하기 (1) | 2018.07.08 |
댓글 영역