[Effective Modern C++] 항목 4. 연역된 형식을 파악하는 방법을 알아두라
이번 항목에서는 연역된 형식이 무엇인지 궁금할 때, 형식을 알아내는 방법에 대해서 소개한다. 예를 들면 auto를 사용하는 경우인데 이를 알아내기란 쉽지가 않다. 이 책에서는 형식을 알아낼 수 있는 3가지 방법을 소개했다.
- IDE 편집기
- 컨파일러의 진단 메시지
- 실행시점 출력
IDE 편집기
좋은 IDE를 사용하고 있다면 현재 연역된 형식이 무엇인지 알려준다. 일반적으로 타입에 마우스를 올려두기만 하면된다. 그러나 복잡한 형식에서는 IDE가 알려주지 못할 수도 있다.
컨파일러의 진단 메시지
decltype 과 template 을 이용해서 컨파일러 에러를 통해 알아내는 방법이다. 방법은 다음과 같다.
template<typename T>
class TD;
TD<decltype(x)> xType; // 컴파일 에러
TD<decltype(y)> yType; // 컴파일 에러
xType과 yType을 선언한 부분에서 컴파일 에러가 나타나며 x와 y의 타입이 무엇인지 알려줄 것이다.
실행시점 출력
typeid와 std::type_info::name
이 방법은 로그를 이용해서 확인하는 방법이다. 먼저 typeid와 std::type_info::name 을 사용하는 방법이 있다.
cout << typeid(x).name() << endl;
그러나 여기에 문제가 하나 있다.
template<typename T>
void f(const T& param)
{
cout << typeid(T).name() << endl;
cout << typeid(param).name() << endl;
}
std::vector<Widget> createVec();
const auto vw = createVec();
f(&vw[0]);
위 함수에서 결과는 T 와 param 모두 const Widget* 라고 나타난다. param 과 T 의 타입이 같은게 말이 되지 않는다. 왜 다른걸까?
그 이유는 param 의 형식을 일부러 틀리기 때문이다. 표준에 따르면 std::type_info::name 은 값 전달 매개변수로 취급해야하기 때문이다. 실제 param 의 형식은 const Widget * const& 인데 값 전달이기 때문에 뒤에 나타난 const 와 참조가 사라지게 되는 것이다.
boost 라이브러리의 typeindex
보다 정확한 형식을 알아내는 방법은 바로 typeindex를 사용하는 것이다.
template<typename T>
void f(const T& param)
{
cout << type_id_with_cvr<T>().pretty_name() << endl;
cout << type_id_with_cvr<decltype(param)>().pretty_name() << endl;
}
type_id_with_cvr 함수에서 cvr이 붙은 이유가 바로 const 와 volatile, reference (참조성)을 유지하기 때문이다.
참고 서적
스콧 마이어스, Effective Modern C++