Есть ли способ создать уникальный тип Id во время компиляции в C ++ - PullRequest
0 голосов
/ 04 февраля 2019

Я могу создать уникальный идентификатор типа следующим образом:

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 голосов
/ 04 февраля 2019

В настоящее время в C ++ нет способа автоматически выделить уникальный идентификатор целочисленного типа и сделать его доступным во время компиляции.

Вот почему библиотеки, которым это необходимо, используют ручную регистрацию типов, например:

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)
0 голосов
/ 04 февраля 2019

Это звучит как XY проблема .Если вы хотите получить информацию о типе во время компиляции, используйте для этого способы компиляции.Правильный способ сделать это с 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...