Ich habe eine bestimmte Situation, in der ich einige Laufzeitstrukturen zur Kompilierzeit vorbereiten möchte, ohne Code duplizieren zu müssen.Füllen Laufzeitdaten zur Kompilierzeit mit Vorlagen
Ich habe zwei structs, die ich bei der Kompilierung für einen Compiler einige Typen verwenden, um zu registrieren, schrieb ich:
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!"); };
Diese werden in einer Config-Header mit einem Makro verwendet, die Type<T>
für mehrere Arten spezialisieren Ich benötige:
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 dass diese zu erweitern, um
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"; };
Das funktioniert gut, aber der Compiler erfordert auch eine gewisse Laufzeit Informationen über diese Art, so dass zusätzlich zu diesem I
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;
}
und ähnlichen Funktionen einiger Zusatzfunktionen wie definieren.
Diese Funktionen müssen ohne Template-Argumente funktionieren, so dass TypeID
ein normales Argument sein muss. Aber ich bin erforderlich, um solche Daten in einem separaten Teil des Codes zu initialisieren, zB:
mapTypeName(Type<s32>::value, "s32");
, die ein statisches std::unordered_map<TypeID, std::string>
verwendet. Natürlich impliziert dies auch, dass ich den Code doppelt halten muss, wenn die meisten Informationen bereits zur Kompilierzeit durch die definierten Typen verfügbar sind.
Ich frage mich, ob es einen obskuren Trick gibt, den ich vermisse, der diese verschmelzen könnte, so dassMakro auch die Laufzeitinformationen registriert. Ich bin noch nicht mit etwas gekommen, aber vielleicht gibt es einen cleveren Weg, das zu bewerkstelligen.
Die Zeilennummer wird für '' __LINE__' in unused_registrar_ __LINE__ ## ## Baumuster zur nicht substituiert. Sie müssen ein Hilfsmakro verwenden. – Leon
@Leon: Danke, behoben. –