c++ - Fill runtime data at compile time with templates -
i have specific situation in prepare runtime structures @ compile time without need duplicate code.
i have 2 structs use register @ compile time types compiler wrote:
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 type!"); };
these used in config header macro specialize type<t>
multiple types require:
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)
so these expand
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"; };
this working fine compiler requires runtime information these types, in addition must define auxiliary functions like
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; }
and similar functions.
these functions must work without template arguments, typeid
must normal argument. i'm required initialize such data in separate part of code, eg:
maptypename(type<s32>::value, "s32");
which uses static std::unordered_map<typeid, std::string>
. of course implies must maintain twice code when of information available @ compile time through types defines.
i wondering if there's obscure trick i'm missing coalesce these register_type
macro registers runtime information. haven't come yet maybe there's clever way manage this.
if not particularly concerned performance of registering run-time data map, use inline
function returns reference static
map instance, , generate "dummy" registrar
instances in register_type
macro fill map in constructor.
inline auto& registration_map() { static std::unordered_map<int, std::string> m; return m; } struct registrar { registrar(int id, std::string s) { registration_map()[id] = std::move(s); } }; template <typename t> struct typehelper { }; #define cat3_impl(a, b, c) ## b ## c #define cat3(a, b, c) cat3_impl(a, b, c) #define register_type(id, type) \ template<> struct typehelper<type> { }; \ [[maybe_unused]] registrar cat3(unused_registrar_, __line__, type) {id, #type}; register_type(0, int) register_type(1, float) register_type(2, double) int main() { assert(registration_map()[0] == "int"); assert(registration_map()[1] == "float"); assert(registration_map()[2] == "double"); }
notes:
you may repeated registrations if same
register_type
included in multiple translation units.cat3(unused_registrar_, __line__, type)
used generate unique name not collide otherregister_type
expansions.
Comments
Post a Comment