背景
我正在修改 C++ 中的多态序列化和反序列化。
为此,我使用静态 map :[type id-string] -> [type factory function]
。
每种类型都必须在此映射中注册,我想在编译时进行注册。
方法
最简单的方法是:
/// Creates a concrete serializable type provided as a template parameter
template <typename T>
ISerializable* createSerializable() { return new T; }
/// Factory that registers a serializable type T
template <typename T>
struct SerializableFactory
{
SerializableFactory(const char* type_name)
{
// registerType adds a type_name->factory_function entry to the map
registerType(type_name, createSerializable<T>);
}
};
注册类型是通过宏完成的:
/// Macro that registers the type at compile-time using a static factory instance
#define REGISTER_TYPE(T) \
static SerializableFactory<T> global_##T##Factory(#T);
例如REGISTER_TYPE(ArbitraryClass)
将变成:
static SerializableFactory<ArbitraryClass>
global_ArbitraryClassFactory("ArbitraryClass");
问题
不幸的是,这不适用于 ArbitraryClass<int>
因为<
, >
不允许在标识符中使用。
问题
是否有一个好的解决方法来实现以这种方式注册任意模板类型?
替代方案
我考虑了以下替代方案(每种方案都有缺点):
- 运行时注册类型:看起来不太优雅,需要序列化用户付出更多努力;
- RTTI:需要启用 RTTI,不保证不同类型始终具有不同的哈希值/名称(当然不太可能,但仍然如此);
- 要求用户提供类型别名或别名:不太优雅,序列化用户需要付出更多努力
更新:
- 正如 @Svalorzen 在他的回答中提到的匿名命名空间可以使用。不幸的是,不能在翻译单元中多次使用宏是一个缺点。例如,对于仅 header 类型。
最佳答案
部分解决方案是始终使用相同的名称,但将其包装在未命名的命名空间中。这仅允许您为每个翻译单元注册一个类型,但这也许已经足够了。
/// Macro that registers the type at compile-time using a static factory instance
#define REGISTER_TYPE(T) \
namespace { \
static SerializableFactory<T> serial_global_factory(#T); \
}
否则,您可以使用 __LINE__
和 __FILE__
宏标记为您的对象创建唯一的名称 - 只要您不必在其他地方引用它。还有其他的,列表可以查here .
关于c++ - 为模板类静态实例生成有效标识符的宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42482894/