KoreanFoodie's Study
Effective Modern C++ | 항목 4 : 연역된 형식을 파악하는 방법을 알아두라 본문
Effective Modern C++ | 항목 4 : 연역된 형식을 파악하는 방법을 알아두라
GoldGiver 2022. 10. 26. 09:49
C++ 프로그래머의 필독서이자 바이블인, 스콧 마이어스의 Modern Effective C++ 를 읽고 기억할 내용을 요약하고 있습니다. 꼭 읽어보시길 추천드립니다!
항목 4 : 연역된 형식을 파악하는 방법을 알아두라
핵심 :
1. 컴파일러가 연역하는 형식을 IDE 편집기나 컴파일러 오류 메시지, Boost TypeIndex 라이브러리를 이용해서 파악할 수 있는 경우가 많다.
2. 일부 도구의 결과는 유용하지도 않고 부정확할 수 있으므로, C++ 의 형식 연역 규칙들을 제대로 이해하는 것은 여전히 필요한 일이다.
형식 연역 정보를 얻는 방법은 세 가지 시점으로 분류할 수 있다.
1. IDE 편집기
2. 컴파일러의 진단 메시지
decltype 을 사용하면 다음과 같은 경우, 타입을 컴파일 타임에 알아낼 수 있다.
template<typename T>
class TD;
int main()
{
auto x = 1.0f;
TD<decltype(x)> xType;
auto y = (x);
TD<decltype(y)> yType;
}
다음과 같은 에러 메시지를 출력한다!
aggregate 'TD<float> xType' has incomplete type and cannot be defined (yType 도 동일함)
3. 실행시점 출력
typeid 와 std::typeinfo::name 등을 사용해서 printf 를 하면, 런타임에 해당 변수들의 타입을 알아낼 수 있다.
auto x = 1.0f;
const int* y = new int(10);
std::cout << typeid(x).name() << std::endl; // f
std::cout << typeid(y).name() << std::endl; // PKi
물론 결과값은 컴파일러마다 달라서, 해석하기 어려운 경우도 있다. 그리고 typeid 가 제대로 동작하지 않는 경우도 있는데, 다음 예시를 보자.
class Widget {};
template<typename T>
void f(const T& param)
{
using namespace std;
// T 를 표시 : T = PK6Widget
cout << "T = " << typeid(T).name() << endl;
// param 을 표시 : param = PK6Widget
cout << "param = " << typeid(param).name() << endl;
}
// 팩터리 함수
std::vector<Widget> createVec() { return std::vector<Widget>(10); }
int main()
{
const auto vw = createVec();
if (!vw.empty())
{
f(&vw[0]);
}
}
PK 는 "const 를 가리키는 포인터" 를 뜻한다. 숫자 6은 그냥 클래스 이름(Widget) 의 글자 수이다. 즉, T 와 param 이 둘다 const Widget* 형식임을 출력하고 있다. 즉, const Widget* 라는 뜻이다.
그런데, T 와 param 의 형식이 같은 것은 이상하다. T 는 const Widget* 가 맞지만, param 은 const Widget* const & 형식을 가져야 하기 때문이다. 사실 이는 표준을 준수한 것으로, std::type_info::name 은 주어진 형식을 마치 템플릿 함수에 값 전달매개변수로서 전달된 것처럼 취급해야 한다. 항목 1에서 설명했듯, 값 전달의 경우 참조와 const 성이 제거되어 param 의 형식이 const Widget* 이 된 것이다.
대신 Boost.TypeIndex 을 이용하면 정확한 타입을 얻을 수 있다.
#include <boost/type_index.hpp>
class Widget {};
template<typename T>
void f(const T& param)
{
using namespace std;
using boost::typeindex::type_id_with_cvr;
// T 를 표시 : T = Widget const*
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl;
// param 을 표시 : param = Widget const* const&
cout << "param = " << type_id_with_cvr<decltype(param)>().pretty_name() << endl;
}
boost::typeindex::type_id_with_cvr 은 전달된 형식 인수의 const 나 volatile, 참조 한정사들을 그대로 보존한다!
'Tutorials > C++ : Advanced' 카테고리의 다른 글
Effective Modern C++ | 항목 6 : auto 가 원치 않은 형식으로 연역될 때는 명시적 형식의 초기치를 사용하라 (0) | 2022.10.26 |
---|---|
Effective Modern C++ | 항목 5 : 명시적 형식 선언보다는 auto 를 선호하라 (0) | 2022.10.26 |
Effective Modern C++ | 항목 3 : decltype 의 작동 방식을 숙지하라 (0) | 2022.10.26 |
Effective Modern C++ | 항목 2 : auto 의 형식 연역 규칙을 숙지하라 (0) | 2022.10.26 |
Effective Modern C++ | 항목 1 : 템플릿 형식 연역 규칙을 숙지하라 (0) | 2022.10.26 |