[Modern C++] 항목 4: 연역된 형식을 파악하는 방법을 알아두라
카테고리: Cpp
이 글은 아래의 책을 정리하였습니다. 이펙티브 모던 C++, 스콧 마이어스 저자, 류광 번역
📦 1. 형식 연역
👉🏻 항목 4: 연역된 형식을 파악하는 방법을 알아두라
- 연역된 형식을 파악하는 세 가지 시점
- 코드 작성/수정
- 컴파일 시점
- 실행 시점
1️⃣ 코드 작성/수정
const int theAnswer = 42;
auto x = theAnswer; // 형식 = int
auto y = &theAnswer; // 형식 = const int*
- IDE 편집기를 사용한다.
- 프로그램 개체에 마우스를 올려, 형식을 확인할 수 있다.
- 코드의 상태가, 컴파일러가 코드를 파싱해서 형식 연역을 수행할 수 있는 수준이어야 한다.
- 복잡한 형식이 관여할 때는, 도움이 되지 않을 수 있다.
- 완전히 믿으면 안 된다.
- 뒤에서 나올
std::type_info::name와 비슷하게 힌트로만 사용해야 한다.
- 뒤에서 나올
2️⃣ 컴파일 시점
// TD(Type Displayer)를 선언만 해둠
template<typename T>
class TD;
TD<decltype(x)> xType;
TD<decltype(y)> yType;
// 출력
error: 'xType'은(는) 정의되지 않은 class 'TD<int>'을(를) 사용합니다.
error: 'yType'은(는) 정의되지 않은 class 'TD<const int *>'을(를) 사용합니다.
- 오류를 의도적으로 발생시켜, 컴파일러의 진단 메시지를 확인한다.
3️⃣ 실행 시점
함수 사용
cout << typeid(x).name() << '\n';
cout << typeid(y).name() << '\n';
- GNU, Clang 컴파일러는 특별한 방식으로 보고한다.
int→iconst int*→PKi(PK = pointer to konst)
- Microsoft 컴파일러는 평범하게 보고한다.
template<typename T>
void f(const T& param) {
cout << "T = " << typeid(T).name() << '\n';
cout << "param = " << typeid(param).name() << '\n';
}
vector<Widget> createVec();
const auto vw = createVec();
if(!vw.empty()) {
f(&vw[0]);
...
}
// 출력 (Microsoft 컴파일러)
T = class Widget const *
param = class Widget const * // ⚠️ 틀림
param은class const Widget * const &으로 나왔어야 했다.- 항목 1의
ParamType이 포인터/참조 형식이지만, 보편 참조는 아닌 경우에 해당
- 항목 1의
std::type_info::name는 믿을 만하지 않다.- 템플릿 함수에 값 전달 매개변수로 전달된 것처럼 취급한다.
const,volatile,참조가 무시된다.
Boost 라이브러리 사용
#include <boost/type_index.hpp>
template<typename T>
void f(const T& param) {
using boost::typeindex::type_id_with_cvr;
cout << "T = " << type_id_with_cvr<T>().pretty_name() << '\n';
cout << "param = " << type_id_with_cvr<decltype(param)>().pretty_name() << '\n';
}
// 출력 (Microsoft 컴파일러)
T = class Widget const *
param = class Widget const * const &
type_id_with_cvr은const,volatile,참조를 보존한다.
🧐 정리
- 컴파일러가 연역하는 형식을 IDE 편집기, 컴파일러 오류 메시지, Boost 라이브러리를 통해 파악할 수 있는 경우가 많다.
- 일부 도구는 유용하지 않고 정확하지 않을 수도 있으므로, C++ 형식 연역 규칙을 이해해야 한다.
댓글남기기