我有一個特定的情況,我想在編譯時準備一些運行時結構而不需要重複代碼。使用模板在編譯時填充運行時數據
我有使用在編譯時註冊一些類型的編譯器我寫了兩個結構:
using TypeID = u8;
template<typename T, typename TYPE_ID, TYPE_ID I>
struct TypeHelper
{
static constexpr TYPE_ID value = std::integral_constant<TYPE_ID, I>::value;
};
template<typename T> struct Type : TypeHelper<T, u8, __COUNTER__> { static_assert(!std::is_same<T,T>::value, "Must specialize for type!"); };
這些在配置頭使用專門Type<T>
對多種類型的我需要一個宏:
using type_size = unsigned char;
#define GET_NTH_MACRO(_1,_2,_3, NAME,...) NAME
#define REGISTER_TYPE(...) GET_NTH_MACRO(__VA_ARGS__, REGISTER_TYPE3, REGISTER_TYPE2, REGISTER_TYPE1)(__VA_ARGS__)
#define REGISTER_TYPE1(_TYPE_) REGISTER_TYPE2(_TYPE_, _TYPE_)
#define REGISTER_TYPE2(_TYPE_,_NAME_) \
constexpr TypeID TYPE_##_NAME_ = __COUNTER__; \
template<> struct Type<_TYPE_> : TypeHelper<_TYPE_, type_size, TYPE_##_NAME_> { \
static constexpr const char* name = #_NAME_; \
};
REGISTER_TYPE(void)
REGISTER_TYPE(s64)
REGISTER_TYPE(s32)
使這些擴展到
constexpr TypeID TYPE_void = 2;
template<> struct Type<void> : TypeHelper<void, type_size, TYPE_void> { static constexpr const char* name = "void"; };
constexpr TypeID TYPE_s64 = 3;
template<> struct Type<s64> : TypeHelper<s64, type_size, TYPE_s64> { static constexpr const char* name = "s64"; };
constexpr TypeID TYPE_s32 = 4;
template<> struct Type<s32> : TypeHelper<s32, type_size, TYPE_s32> { static constexpr const char* name = "s32"; };
這是工作正常,但編譯器也需要了解這些類型的一些運行信息,所以除了這個,我必須這樣定義
static TypeID typeForIdent(const std::string& name);
static const char* nameForType(TypeID type);
static void mapTypeName(TypeID type, const std::string& name);
inline bool isSigned(TypeID type)
{
return type == Type<s8>::value || type == Type<s16>::value ||
type == Type<s32>::value || type == Type<s64>::value;
}
和類似功能的一些輔助功能。
這些函數必須在沒有模板參數的情況下工作,因此TypeID
必須是普通參數。但我需要的代碼一個單獨的部分來初始化這樣的數據,例如:
mapTypeName(Type<s32>::value, "s32");
它使用一個靜態std::unordered_map<TypeID, std::string>
。當然這也意味着當編譯時通過類型定義已經有大部分信息可用時,我必須維護兩次代碼。
我想知道是否有一些晦澀的技巧,我可能會合並這些,以便REGISTER_TYPE
宏也註冊運行時信息。我還沒有拿出任何東西,但也許有一個聰明的方法來管理這件事。
行號在'unused_registrar_ ## __LINE__ ## type'中不會被__LINE__替代。您必須使用助手宏。 – Leon
@Leon:謝謝,修正。 –