支持相等比较的类的constexpr ID

时间:2016-05-02 13:04:59

标签: c++ metaprogramming c++14 constexpr

我需要为我的C ++类创建一个唯一的constexpr ID。另一个要求是这些ID应该具有可比性(如果可以与><进行比较,那就更好了。

想到一个简单的解决方案:

template <typename T>
struct IDMaker {
    static int i;
    static constexpr void * id = &i;
}

这种方法的问题在于以下无法在constexpr上下文中编译:

IDMaker<int>::id == IDMaker<double>::id;

id似乎constexpr,但其比较不是。我已经对此进行了一些实验,并且在id上下文中对constexpr constexpr实际上没什么用处。 (编辑:这是GCC 5.3中的一个错误,根据评论中的dyp,clang没有抱怨这个。这是一个GCC错误吗?还是铿锵过于宽容?)

为了给出一点上下文,我需要这个能够使用constexpr函数进行元编程,这样我就可以在运行时重用相同的逻辑。例如,我希望能够编写一个带有两个类型列表的函数,并返回一个数组,该数组包含第二个列表中与第一个列表中的元素匹配的元素的索引。如果我可以获取类的ID,我可以轻松地将其实现为接收两个类型ID数组的constexpr函数。除了在运行时重用constexpr const char * name(){return #NewType;}函数之外,我希望这也会加快我的编译时间。

我实际上有一种解决方案,但它涉及一些宏观魔法;本质上,我使用宏来将类和名称空间的名称反映为constexpr我还可以访问类的命名空间的反射类并获取其名称。我最后编写了一个constexpr size_t hash(const char *str) { size_t result{0}; for(size_t i =0; str[i]!=0; ++i) { ... } return result; } 哈希函数:

constexpr

使用此函数,我可以散列类的完整名称并获得size_t {{1}},并且它可以正常工作。我对这种方法有两个问题:

1)当我有1000个班级时,我的编译时间会有多糟糕?你能推荐一个快速哈希函数吗? 2)如何避免哈希冲突,或者至少在碰撞发生时得到早期错误?

1 个答案:

答案 0 :(得分:1)

要在编译时为类生成ID,可以使用指向函数的指针。我将它实现为模板元函数,它返回一个指向函数的指针并将类型作为参数:

template<typename T>
void id_gen(){}

using type_id_t = void(*)(void);

template<typename T>
constexpr type_id_t type_id = &id_gen<T>;

由于函数id_gen的每个实例都有不同的地址,我们可以将它用作唯一标识符!

然后,你可以为你的类制作一些语法糖:

template<typename Crtp>
struct Identified {
    static constexpr type_id_t ID = type_id<Crtp>;
};

现在要识别你的类,你只需要使用继承:

struct A : Identified<A> {};
struct B : Identified<B> {};

此解决方案的优点:

  • 没有碰撞
  • 编译时间非常快
  • std::map
  • 中易于使用

此解决方案的缺点:

  • ID生成仅限编译时间
  • 您无法预测值