Войти
ПрограммированиеФорумОбщее

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

Страницы: 1 2 3 Следующая »
#0
17:19, 17 дек. 2017

Переношу базу данных об игровых предметах из крестового хардкода в файлик БД на json. Естественно что все мои enum class для предметов (например ItemType::HealingPotion) пришлось выкинуть и заменить их строковыми аналогами. Вот тут появляется широкое поле для совершения ошибок. Теперь вместо CreateItem(ItemType::HealingPotion) мне приходится писать CreateItem("HealingPotion"). В первом случае компилятор сразу отловит опечатку, а во втором все свалится в рантайме. Отсюда вопрос: есть ли компромиссное решение - и чтоб некорректные значения ловить при компиляции и чтоб в БД их можно было записывать как строки?


#1
17:23, 17 дек. 2017

Вроде в mysql есть тип enum, а если в json... Ну, тут никак уже, только валидировать при загрузке базы в рантайме.

#2
18:05, 17 дек. 2017

Массив имен же. Чтобы DB_NAMES[ItemType::HealingPotion] == "HealingPotion". Соответственно везде в коде использовать енумы, а при обращении к базе заменять на строки. Синтаксический сахар по вкусу. Правда объявление енума (ну и этот массив) будет хардкодом, но тут уж ничего не поделаешь - если не хардкодить, то как компилятор сможет узнать.

#3
18:17, 17 дек. 2017

Ну кодоген же так и просится.

#4
20:19, 17 дек. 2017

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;
...
}

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

#5
20:20, 17 дек. 2017

FordPerfect
Слишком накладно вроде, или я чего-то не знаю про кодогенерацию?

#6
21:16, 17 дек. 2017

mr.DIMAS
Ну что то подобное и должно получится. Иначе никак.

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

#7
21:21, 17 дек. 2017

Андрей5000
> А это что такое?
Сериализация. Перегруженный оператор &, который либо сохраняет значение в файл, либо восстанавливает его из файла.

#8
2:54, 18 дек. 2017

mr.DIMAS
> Сериализация. Перегруженный оператор &, который либо сохраняет значение в файл,
> либо восстанавливает его из файла.
<< >> более наглядно ведь.

#9
3:31, 18 дек. 2017

mr.DIMAS
оо, у нас на этом собаку съели. когда количество статов (элементов енама, кстати, сгенерированных кодгеном) перевалило за несколько тысяч и всем надоело пересобирать весь проект каждый раз, когда добавляется новый элемент, было решено перерефакторить всё это дело. как я понял, план в том, чтобы использовать строковые идентификаторы, для которых в компайлтайме вычисляется и проверяется хэш. то есть обращаться в духе

float val = stats[HASH("inc_damage_per_troll_in_current_thread_on_mondays")];
в дебаге функция HASH автоматически пробегается по базе известных статов и проверяет, что строка с указанным статом действительно в базе существует. в релизе просто генерит хэш для строки в компайлтайме для быстрого доступа.
#10
10:28, 18 дек. 2017

Suslik
Круто, у меня элементов на порядок меньше (всего 200), но перекомпиляция тоже надоедает. Надо попробовать такой подход.

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

#11
14:00, 18 дек. 2017

mr.DIMAS
Набор заранее определённых строк с валидацией что такие предметы есть в базе.

#12
21:26, 18 дек. 2017

Утилку кодогенерации и тупо дефайнами, KISS

#13
6:02, 19 дек. 2017

Объясните, пожалуйста, зачем такие вещи (изначально) хардкодить? Особенно, как enum?

#14
6:09, 19 дек. 2017

skalogryz
> Объясните, пожалуйста, зачем такие вещи (изначально) хардкодить? Особенно, как enum?
потому что как можно больше проверок нужно по возможности переносить в компайлтайм. если ты неправильно написал имя стата, то лучше, чтобы программа просто не скомпилировалась, чем когда-нибудь там, возможно, упала.

Страницы: 1 2 3 Следующая »
ПрограммированиеФорумОбщее

Тема в архиве.