宏为模板类静态实例生成有效标识符

时间:2017-02-27 10:07:45

标签: c++ c++11 templates macros

背景

我正在修改C ++中的多态序列化和反序列化。 为此,我使用静态地图:[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>因为<>uwsgi --http :8080 --home /home/flybegins/python/django/venv/ --chdir /home/flybegins/python/django/sample -w sample.wsgi 不允许在标识符中使用。

问题

通过这种方式实现注册任意模板类型是否有良好的解决方法?

替代

我考虑了以下备选方案(每种方案都有缺点):

  • 注册类型运行时:看起来不太优雅,需要序列化用户付出更多努力;
  • RTTI :要求启用RTTI,不保证不同类型的哈希/名称总是不同(当然不太可能,但仍然如此);
  • 要求用户提供类型别名或别名:不那么优雅,来自序列化用户的更多努力

更新

  • 正如@Svalorzen在回答匿名命名空间中提到的那样。不幸的是,不能在翻译单元中多次使用宏是一个缺点。例如,仅限标题类型。

3 个答案:

答案 0 :(得分:2)

部分解决方案是始终使用相同的名称,但将其包装在未命名的命名空间中。这只允许你为每个翻译单元注册一个类型,但这可能就足够了。

/// 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

答案 1 :(得分:1)

我有一个啊哈!时刻的灵感来自@ W.F的评论。 ,@ Svalorzen回答,this回答。我认为这是一个非常聪明的伎俩,没有替代方案的缺点。

解决方案:使用未命名/匿名命名空间 __LINE__添加到标识符应始终提供唯一标识符(除非宏在同一行使用了两次。)

以下是它的外观:

#define MERGE(A, B) A##B
#define CREATE_UNIQUE_IDENTIFIER(line) MERGE(unique_identifier_on_line_, line)
/// UNIQUE_IDENTIFIER generates identifiers like:
/// "unique_identifier_on_line_" + line_number
#define UNIQUE_IDENTIFIER CREATE_UNIQUE_IDENTIFIER(__LINE__)
/// Macro that registers the type at compile-time using a static factory instance
#define REGISTER_TYPE(T)                                                   \
    namespace                                                              \
    {                                                                      \
    static SerializableFactory<T> UNIQUE_IDENTIFIER(#T);                   \
    }

答案 2 :(得分:0)

尝试将类型定义为单个名称并使用名称:

typedef ArbitraryClass<int> ArbitraryClass_int_;
REGISTER_TYPE(ArbitraryClass_int_);

您也可以尝试将其放在哈希映射中,其中键是typename。