几个月前我遇到了类似的问题。我一直在寻找一种技术来定义每次执行时都相同的标识符。
如果这是一个要求,那么这里是另一个探索或多或少相同问题的问题(当然,它带有很好的答案)。
无论如何,我没有使用建议的解决方案。它遵循了我当时所做的事情的描述。
您可以定义constexpr
如下函数:
static constexpr uint32_t offset = 2166136261u;
static constexpr uint32_t prime = 16777619u;
constexpr uint32_t fnv(uint32_t partial, const char *str) {
return str[0] == 0 ? partial : fnv((partial^str[0])*prime, str+1);
}
inline uint32_t fnv(const char *str) {
return fnv(offset, str);
}
然后是这样的类来继承:
template<typename T>
struct B {
static const uint32_t id() {
static uint32_t val = fnv(T::identifier);
return val;
}
};
剩下的就是 CRTP 成语。
例如,您可以定义一个派生类,如下所示:
struct C: B<C> {
static const char * identifier;
};
const char * C::identifier = "ID(C)";
只要你为不同的类提供不同的标识符,你就会有唯一的数值,可以用来区分类型。
标识符不需要是派生类的一部分。例如,您可以通过 trait 提供它们:
template<typename> struct trait;
template<> struct trait { static const char * identifier; };
// so on with all the identifiers
template<typename T>
struct B {
static const uint32_t id() {
static uint32_t val = fnv(trait<T>::identifier);
return val;
}
};
优点:
- 易于实施。
- 没有依赖关系。
- 每次执行期间数值都相同。
- 如果需要,类可以共享相同的数字标识符。
缺点:
它遵循上面描述的一个最小的工作示例。
我修改了代码,以便能够在语句中使用ID
成员方法:switch
#include<type_traits>
#include<cstdint>
#include<cstddef>
static constexpr uint32_t offset = 2166136261u;
static constexpr uint32_t prime = 16777619u;
template<std::size_t I, std::size_t N>
constexpr
std::enable_if_t<(I == N), uint32_t>
fnv(uint32_t partial, const char (&)[N]) {
return partial;
}
template<std::size_t I, std::size_t N>
constexpr
std::enable_if_t<(I < N), uint32_t>
fnv(uint32_t partial, const char (&str)[N]) {
return fnv<I+1>((partial^str[I])*prime, str);
}
template<std::size_t N>
constexpr inline uint32_t fnv(const char (&str)[N]) {
return fnv<0>(offset, str);
}
template<typename T>
struct A {
static constexpr uint32_t ID() {
return fnv(T::identifier);
}
};
struct C: A<C> {
static constexpr char identifier[] = "foo";
};
struct D: A<D> {
static constexpr char identifier[] = "bar";
};
int main() {
constexpr auto val = C::ID();
switch(val) {
case C::ID():
break;
case D::ID():
break;
default:
break;
}
}
请注意,如果您想ID
在非常量表达式中使用,您必须在某处定义identifier
s,如下所示:
constexpr char C::identifier[];
constexpr char D::identifier[];
完成后,您可以执行以下操作:
int main() {
constexpr auto val = C::ID();
// Now, it is well-formed
auto ident = C::ID();
// ...
}