Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / [C++] Строки как замена enum

[C++] Строки как замена enum

Страницы: 1 2 3 Следующая »
mr.DIMASПостоялецwww17 дек. 201717:19#0
Переношу базу данных об игровых предметах из крестового хардкода в файлик БД на json. Естественно что все мои enum class для предметов (например ItemType::HealingPotion) пришлось выкинуть и заменить их строковыми аналогами. Вот тут появляется широкое поле для совершения ошибок. Теперь вместо CreateItem(ItemType::HealingPotion) мне приходится писать CreateItem("HealingPotion"). В первом случае компилятор сразу отловит опечатку, а во втором все свалится в рантайме. Отсюда вопрос: есть ли компромиссное решение - и чтоб некорректные значения ловить при компиляции и чтоб в БД их можно было записывать как строки?
Red_Baron_Постоялецwww17 дек. 201717:23#1
Вроде в mysql есть тип enum, а если в json... Ну, тут никак уже, только валидировать при загрузке базы в рантайме.

Правка: 17 дек. 2017 17:23

kiparУчастникwww17 дек. 201718:05#2
Массив имен же. Чтобы DB_NAMES[ItemType::HealingPotion] == "HealingPotion". Соответственно везде в коде использовать енумы, а при обращении к базе заменять на строки. Синтаксический сахар по вкусу. Правда объявление енума (ну и этот массив) будет хардкодом, но тут уж ничего не поделаешь - если не хардкодить, то как компилятор сможет узнать.
FordPerfectПостоялецwww17 дек. 201718:17#3
Ну кодоген же так и просится.
mr.DIMASПостоялецwww17 дек. 201720:19#4
kipar
Сделал как-то так
//
// .h
//
class DamageClass {
public:
  enum Type { Unknown, Physical, Chemical, Electrical, Fire, Count };
  
  static unordered_map<string, Type> Names;
private:
  Type mValue{Unknown};

public:
  DamageClass() {
  }
  DamageClass(const string &str) {
    auto iter = Names.find(str);
    if (iter == Names.end()) {
      throw runtime_error("Invalid damage class: " + str);
    }
    mValue = iter->second;
  }
  DamageClass(const Type &type) : mValue(type) {
  }
  bool operator==(const Type &other) const {
    return mValue == other;
  }
  bool operator==(const DamageClass &other) const {
    return mValue == other.mValue;
  }
  operator Type() const {
    return mValue;
  }
  void Serialize(Serializer &sav) {
    sav &mValue;
  }
};

//
// .cpp
//

#define ENTRY(x) {#x, x}

unordered_map<string, DamageClass::Type> DamageClass::Names = {
  ENTRY(Unknown), 
  ENTRY(Physical),
  ENTRY(Chemical), 
  ENTRY(Electrical), 
  ENTRY(Fire), 
  ENTRY(Count)
};

Используется это так же как enum class

auto dmgClass = DamageClass::Physical;
...
switch(dmgClass) {
case DamageClass::Physical:
...
break;
case DamageClass::Chemical:
...
break;
...
}

Контролировать все равно приходится ручками, но тут намного надежнее чем со строками по всему коду.

mr.DIMASПостоялецwww17 дек. 201720:20#5
FordPerfect
Слишком накладно вроде, или я чего-то не знаю про кодогенерацию?
Андрей5000Постоялецwww17 дек. 201721:16#6
mr.DIMAS
Ну что то подобное и должно получится. Иначе никак.

А это что такое?
> sav &mValue;

mr.DIMASПостоялецwww17 дек. 201721:21#7
Андрей5000
> А это что такое?
Сериализация. Перегруженный оператор &, который либо сохраняет значение в файл, либо восстанавливает его из файла.
ArochПостоялецwww18 дек. 20172:54#8
mr.DIMAS
> Сериализация. Перегруженный оператор &, который либо сохраняет значение в файл,
> либо восстанавливает его из файла.
<< >> более наглядно ведь.
SuslikМодераторwww18 дек. 20173:31#9
mr.DIMAS
оо, у нас на этом собаку съели. когда количество статов (элементов енама, кстати, сгенерированных кодгеном) перевалило за несколько тысяч и всем надоело пересобирать весь проект каждый раз, когда добавляется новый элемент, было решено перерефакторить всё это дело. как я понял, план в том, чтобы использовать строковые идентификаторы, для которых в компайлтайме вычисляется и проверяется хэш. то есть обращаться в духе
float val = stats[HASH("inc_damage_per_troll_in_current_thread_on_mondays")];
в дебаге функция HASH автоматически пробегается по базе известных статов и проверяет, что строка с указанным статом действительно в базе существует. в релизе просто генерит хэш для строки в компайлтайме для быстрого доступа.

Правка: 18 дек. 2017 3:32

mr.DIMASПостоялецwww18 дек. 201710:28#10
Suslik
Круто, у меня элементов на порядок меньше (всего 200), но перекомпиляция тоже надоедает. Надо попробовать такой подход.

Aroch
> << >> более наглядно ведь.
У меня Serialize универсальный метод - он и для сериализации и для десериализации одновременно. Поэтому и оператор &.

zlosУдалёнwww18 дек. 201714:00#11
mr.DIMAS
Набор заранее определённых строк с валидацией что такие предметы есть в базе.
key0Постоялецwww18 дек. 201721:26#12
Утилку кодогенерации и тупо дефайнами, KISS
skalogryzУчастникwww19 дек. 20176:02#13
Объясните, пожалуйста, зачем такие вещи (изначально) хардкодить? Особенно, как enum?

Правка: 19 дек. 2017 6:03

SuslikМодераторwww19 дек. 20176:09#14
skalogryz
> Объясните, пожалуйста, зачем такие вещи (изначально) хардкодить? Особенно, как enum?
потому что как можно больше проверок нужно по возможности переносить в компайлтайм. если ты неправильно написал имя стата, то лучше, чтобы программа просто не скомпилировалась, чем когда-нибудь там, возможно, упала.
Страницы: 1 2 3 Следующая »

/ Форум / Программирование игр / Общее

2001—2018 © GameDev.ru — Разработка игр