Определите тип поля из типа поля класса шаблона вместо добавления дополнительного класса в шаблон

У меня есть общий класс кэширования (пример упрощен по сравнению с тем, что есть в моей кодовой базе). Элементы хранятся на карте, а тип шаблона T должен иметь поле id, чтобы я мог сохранить его на карте.

struct Car
{
  int id;
  std::string name;
};

struct Aeroplane
{
  std::string id;
  int top_speed;
  std::string brand;
};

template<class T, class S>
class Cache
{
public:
  void Add(T item)
  {
    cache.emplace(item.id, item);    
  }

  bool Contains(T item)
  {
    return cache.find(item.id) != cache.end();
  }

private:
  map<S, T> cache;
};

int main()
{
  Cache<Car, int> cars;
  // we can add Car instances to cars here

  Cache<Aeroplane, std::string> aeroplanes;
  // we can add Aeroplane instances to aeroplanes here

}

На данный момент класс S может быть любым, но он должен быть того же типа, что и T.id. Было бы очень хорошо, если бы мы могли сказать, что кеш должен быть картой из типа T.id в T. Тогда я могу упростить шаблонизацию, удалив класс S.

template<class T>
class Cache
{
public:
  ... should be same as above ...

private:
  // is it possible?
  map< /* the type of T.id ??? */ , T> cache;
};

int main()
{
  // it would be very nice if we can simplify it, so that the definition looks like this
  Cache<Car> cars;

  // and...
  Cache<Aeroplane> aeroplanes;
}

Кто-нибудь знает, как мне это сделать?

decltype(T::id)?
Mike Vine 11.12.2020 14:34

До C++11 вы могли заставить класс иметь typedef: typedef int id_type;.

Jarod42 11.12.2020 15:06
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать decltype, чтобы получить тип выражения. И выражение на самом деле не будет выполняться, а просто оцениваться с точки зрения типа.

Таким образом, вы можете сделать что-то вроде

template<class T, class S = decltype(T().id)>
class Cache
{
    ...
}

Это гарантирует, что S имеет тот же тип, что и id в экземпляре T.

Ответ принят как подходящий

Вы можете указать значение по умолчанию для S следующим образом:

template<class T, class S = decltype(std::declval<T>().id)>
class Cache
{
public:
  void Add(T item)
  {
    cache.emplace(item.id, item);    
  }

  bool Contains(T item)
  {
    return cache.find(item.id) != cache.end();
  }

private:
  map<S, T> cache;
};

int main()
{
  Cache<Car> cars;
  // we can add Car instances to cars here

  Cache<Aeroplane> aeroplanes;
  // we can add Aeroplane instances to aeroplanes here

}

Или избавьтесь от второго параметра шаблона, например:

template<class T>
class Cache
{
public:
  using S = decltype(std::declval<T>().id);
  // ...
  map<S, T> cache;
};

Или короче (спасибо @MikeVine):

template<class T>
class Cache
{
public:
  using S = decltype(T::id);
  // ...
  map<S, T> cache;
};

В чем преимущество decltype(std::declval<T>().id) перед decltype(T::id)?

Mike Vine 11.12.2020 14:42

@MikeVine нет. Разница между ними в том, что я не знал, что decltype(T::id) компилируется;) Я добавлю это к ответу. Спасибо

463035818_is_not_a_number 11.12.2020 14:46

Я запускаю его с помощью g++, и первый и второй варианты прекрасно работают. Моему g++ не нравится третий. Но этого достаточно для меня. Спасибо.

Ferry Utomo 12.12.2020 20:14

Без проблем скомпилировать все параметры с помощью g++ с языковой версией C++17.

Ferry Utomo 12.12.2020 21:28

Другие вопросы по теме