每种类型的编译时类型ID
compile time typeid for every type
我想要一个constexpr
函数,它将为每个C++类型返回一个唯一的id,如下所示:
using typeid_t = uintptr_t;
template <typename T>
constexpr typeid_t type_id() noexcept
{
return typeid_t(type_id<T>);
}
int main()
{
::std::cout << ::std::integral_constant<typeid_t, type_id<float>()>{} << ::std::endl;
return 0;
}
但是我得到一个错误:
t.cpp: In function 'int main()':
t.cpp:23:69: error: conversion from pointer type 'typeid_t (*)() noexcept {aka long unsigned int (*)() noexcept}' to arithmetic type 'typeid_t {aka long unsigned int}' in a constant-expression
::std::cout << ::std::integral_constant<typeid_t, type_id<float>()>{} << ::std::endl;
^
t.cpp:23:69: note: in template argument for type 'long unsigned int'
有没有解决方法或其他方法?
您可以使用一些技巧,如本答案所示。
甚至还有一个名为ctti的库使用了相同的技巧,它应该开箱即用。
static_assert(ctti::type_id<int>() != ctti::type_id<float>(), "compile-time type-id comparison");
constexpr auto hash = ctti::type_id<int>().hash();
另一种方法,这次涉及constexpr
函数,是使用一个众所周知的哈希函数,如以下示例所示(我使用了 FNV v1a):
#include <cstdint>
#include <iostream>
static constexpr uint32_t offset = 2166136261u;
static constexpr uint32_t prime = 16777619u;
constexpr uint32_t helper(uint32_t partial, const char *str) {
return str[0] == 0 ? partial : helper((partial^str[0])*prime, str+1);
}
constexpr uint32_t hash_str(const char *input) {
return helper(offset, input);
}
struct MyClassA { static constexpr uint32_t type = hash_str("MyClassA"); };
struct MyClassB { static constexpr uint32_t type = hash_str("MyClassB"); };
int main() {
std::cout << "MyClassA: " << MyClassA::type << std::endl;
std::cout << "MyClassB: " << MyClassB::type << std::endl;
}
缺点:
- 可能发生冲突
- 容易出错(至少从我的角度来看)
- 相当侵入性 A 解决
主要优点是,如果您需要在不同执行中类型相同(例如,如果您必须将它们存储在某个地方并在一段时间后再次使用它们),则可以使用此解决方案。
这不是一个constexpr
函数,但是如果没有约束类型在多次执行中持久化,则可以使用CRTP
习语作为替代方法来实现相同的结果。
它遵循一个最小的工作示例:
#include <cstddef>
#include <iostream>
struct BaseClass {
protected:
static std::size_t next() noexcept {
static std::size_t counter = 0;
return counter++;
}
};
template<class D>
struct Base: public BaseClass {
static std::size_t type() noexcept {
static std::size_t type_ = BaseClass::next();
return type_;
}
};
struct A: public Base<A> { };
struct B: public Base<B> { };
int main() {
std::cout << A::type() << std::endl;
std::cout << B::type() << std::endl;
}
这样,您就有一个基类,可以从中派生您希望拥有唯一标识符的所有类型。
相关文章:
- 使用类型id运算符的最佳替代方法
- 类型ID,如何仅获取类型名称
- 自动初始值设定项类型ID 信息
- 类型ID指针和引用比较差异?
- gcc 发出了与解析新表达式中的类型 ID 相关的错误
- 我可以从静态基方法获取当前类类型 ID 吗?
- 关于C++中的类型id函数
- reinterpret_cast<类型ID>"type-id"可以是变量吗?
- 我想看到一个在整个后缀表达式的上下文中查找转换类型 id 的示例
- 每种类型的编译时类型ID
- C++模板和类型 ID
- C++类型比较:类型 ID 与双重调度dynamic_cast
- 编译时生成的常量类型 ID
- 类型id(T) 是在运行时还是在编译时被计算
- 如何在编译时生成密集的唯一类型ID
- 类型ID 和type_info类
- 函数未在类型id中调用
- 多态指针的类型id
- 类型id结果不匹配
- 类型ID的成本是多少?