有没有一种方法可以在C ++编译时创建唯一类型Id

时间:2019-02-04 10:22:23

标签: c++11

我可以通过以下方式创建唯一的类型ID:

template<typename T>
struct TypeId
{
  static size_t value()
  {
    return reinterpret_cast<size_t>(&TypeId<T>::value);
  }
};


auto intType = TypeId<int>::value();

它在运行时有效,但是有没有办法在编译时完成? 我想在这样的switch语句中使用它:

switch (typeId)
{
  case TypeId<int>::value():
    // do something
    break;

  case TypeId<double>::value():
    // do something
    break;

  case TypeId<MyClass>::value():
    // do something
    break;
}

这里的问题是我不能在编译时将指针转换为size_t:

template<typename T>
struct TypeId
{
  static constexpr size_t value()
  {
    return reinterpret_cast<size_t>(&TypeId<T>::value);
  }
};

constexpr auto id = TypeId<int>::value();

上面的示例给出了以下错误:

error: conversion from pointer type ‘size_t (*)() {aka long unsigned int (*)()}’ to arithmetic type ‘size_t {aka long unsigned int}’ in a constant expression
   constexpr auto id = TypeId<int>::value();

更新

我想理解为什么在constexpr中返回一个地址是可以的,但是将其转换为int却不是。编译以下代码(但是我不能在switch语句中使用指针):

template<typename T>
struct TypeId
{
  static constexpr void* value()
  {
    return reinterpret_cast<void*>(&TypeId<T>::value);
  }
};

constexpr void* id = TypeId<int>::value();
std::cout << "id: " << id << std::endl;

2 个答案:

答案 0 :(得分:2)

这听起来像XY problem。如果要获取编译时类型信息,请使用编译时方法来执行此操作。正确的方法是使用std::is_same

if(std::is_same<int, T>::value) {
    // do something
} else if (std::is_same<double, T>::value) {
    // do something else
} // ...

可以引起某些问题。如果您在条件中使用特定类型的方法(例如std::string::length()),则会出现编译错误。有解决此问题的方法:

  1. 使用if constexpr
  2. 使用std::enable_if创建依赖于类型的模板专门化
  3. 如果仅遇到指针类型的问题,则必须reinterpret_cast指向T的所有指针

答案 1 :(得分:0)

C ++当前没有办法自动 分配唯一的整数类型id并使其可用于编译时。

这就是为什么需要它的库使用手动类型注册的原因,例如:

template<class T> struct TypeId;

#define REGISTER_TYPE_ID(T, id_value) template<> struct TypeId<T> { static constexpr int id = id_value; };

REGISTER_TYPE_ID(bool,                1)
REGISTER_TYPE_ID(char,                2)
REGISTER_TYPE_ID(unsigned char,       3)
REGISTER_TYPE_ID(unsigned short,      4)
REGISTER_TYPE_ID(unsigned int,        5)
REGISTER_TYPE_ID(unsigned long,       6)
REGISTER_TYPE_ID(unsigned long long,  7)
REGISTER_TYPE_ID(signed char,         8)
REGISTER_TYPE_ID(signed short,        9)
REGISTER_TYPE_ID(signed int,         10)
REGISTER_TYPE_ID(signed long,        11)
REGISTER_TYPE_ID(signed long long,   12)
REGISTER_TYPE_ID(float,              13)
REGISTER_TYPE_ID(double,             14)
REGISTER_TYPE_ID(long double,        15)