我需要为我的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)如何避免哈希冲突,或者至少在碰撞发生时得到早期错误?
答案 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
此解决方案的缺点: