개발하는 리프터 꽃게맨입니다.
C++ RTTI 오버헤드 없는 Type Info 본문
#include <iostream>
#include <typeinfo>
#include <unordered_set>
#include <unordered_map>
struct TypeID
{
bool operator==(const TypeID& other) const
{
return ID == other.ID;
}
size_t ID = {};
};
namespace std
{
template <>
struct hash<TypeID>
{
size_t operator()(const TypeID& typeID) const
{
return std::hash<size_t>{}(typeID.ID);
}
};
}
class TypeInfoBase
{
protected:
static TypeID InstTypeID()
{
TypeID result = { };
result.ID = m_currentTypeID;
m_currentTypeID += ID_COUNT_STEP;
return result;
}
private:
enum {ID_COUNT_STEP = 256};
inline static size_t m_currentTypeID = 0;
};
template <typename Type>
class TypeInfo : TypeInfoBase
{
public:
static TypeID GetID()
{
static TypeID id = InstTypeID();
return id;
}
static const char* GetName()
{
static const char* typeName = typeid(Type).name();
return typeName;
}
};
std::unordered_map<TypeID, std::string> um;
void Insert(TypeID key, std::string str)
{
um[key] = str;
}
int main()
{
Insert(TypeInfo<int>::GetID(), "Hello");
Insert(TypeInfo<float>::GetID(), "My");
Insert(TypeInfo<char>::GetID(), "Name");
Insert(TypeInfo<std::string>::GetID(), "Is");
Insert(TypeInfo<short>::GetID(), "CM");
return 0;
}
typeid는 다형성을 가진 클래스 안에서만 RTTI로 돕니다.
그래서 현재 위 코드는 RTTI를 비활성화 한 상태에서도 잘 돌아갑니다.
typeid로 해쉬테이블을 사용하면 좋을 것 같아서 만들어봤습니다.
typeid.hash 를 사용하면 되지 않느냐.. 라고 의문을 가질 수 있으나
hash를 호출할 때마다 중복된 해쉬 계산을 하니 그게 좀 마음에 걸렸습니다.
이렇게 하면 ID를 한 번만 계산하고 재호출시에는 캐싱된 ID를 가져와서 사용합니다.
InitTypeID 내부 구현을 고치면 ID를 만들어내는 매커니즘을 바꿀 수 있습니다.
해쉬 함수를 사용하는게 일반적이겠죠.