Имеется ли число в enum

370
16 января 2017, 20:33

Программа читает число с flash-памяти внешнего устройства (целое, 1 байт, беззнаковое). Для его программной интерпретации используется перечисление:

enum BoardType {
    Classic = 0,
    Static = 1,
    Smart = 2
}
BoardType t = (BoardType)getBoardType();

Проблема видна невооружённым взглядом: число, содержащееся в памяти, не обязательно содержится в enum. И я думаю, что в runtime никак не проверить, корректно ли возвращённое число, а оно будет обязательно, ведь во flash-памяти в стёртом состоянии хранятся значения 0xFF, а также могут попадать другие числа, которые оказались там из-за моих кривых рук. Итак, есть ли способ проверить, содержится ли возвращённое число в enum, а если нет, то как правильно программно интерпретировать это число?

Answer 1

Я бы предложил, коль речь идет о быстродействии и небольшом количестве команд - использовать просто табличные преобразования. Да и таблица не будет чрезмерно большой.

Пример кода (ссылка на ideone):

#include <iostream>
enum class BoardType : uint8_t { 
  Classic = 0,
  Static = 1,
  Smart = 2,
  Bad = 255  
};
BoardType Cast[UINT8_MAX];     // <- сюда просто забить константы -++
                                                                   //
inline BoardType ToEnum(const uint8_t i) {                         //
  BoardType Ret = Cast[i];                                         //
  if (Ret == BoardType::Bad) throw std::range_error("Беда");       //
  return Ret;                                                      //
}                                                                  //
                                                                   //
int main () {                                                      //
  ////// вместо  инициализации ниже - ///////////////////////////////  
  for(auto i=0; i<UINT8_MAX; i++) Cast[i] = BoardType::Bad;
  Cast[0] = BoardType::Classic;
  Cast[1] = BoardType::Static;
  Cast[2] = BoardType::Smart; 
  //////////////////////////////////////////////////////////////////  
  try {  
    std::cout << static_cast<int>(ToEnum(0)) << std::endl;  
    std::cout << static_cast<int>(ToEnum(1)) << std::endl;
    std::cout << static_cast<int>(ToEnum(2)) << std::endl;
    std::cout << static_cast<int>(ToEnum(3)) << std::endl;  
  } catch(std::range_error &e) {
    std::cout << "range_error: " << e.what() << std::endl;  
  } catch(...) {
    std::cout << "что-то совсем пошло не так" << std::endl;  
  }    
  return 0;        
}

Вывод:

0
1
2
range_error: Беда

Во-первых, можно с помощью функции ToEnum() "неправильные" значения отлавливать в блоках обработки исключений.

Во-вторых, используя таблицу Cast, просто сравнивать с BoardType::Bad, если обработка исключений "напрягает".

В-третьих, если "команд" будет несколько десятков - switch будет хуже читаем, а возможно и медленнее обрабатываем.

Answer 2

По большому счету, никак. Потому что это просто условные обозначения для целочисленных значений.
Так что если уж очень нужно - то либо проверять диапазон (если перечисления без "просветов", либо иметь отдельное множество значений и проверять на присутствие в нем.

По-моему, так. (с) Пух

Answer 3

Конкретно для вашего примера можно так:

enum BoardType{
    Classic = 0,
    Static = 1,
    Smart = 2,
    NumberOfBoardTypes
};
bool isCorrect(BoardType t){
    return t >= 0 && t < NumberOfBoardTypes;
}

Или так:

enum BoardType{
    Classic = 0,
    Static = 1,
    Smart = 2,
    Unknown
};
BoardType getBoardType(){
    BoardType t = static_cast<BoardType>(42);
    if(t < 0 || t > Unknown){
        t = Unknown;
    }
    return t;
}

UPD: для случая с "дырами" в enum можно сделать так:

enum BoardType{
    Classic = 0,
    Static = 1,
    Smart = 2
};
std::set<BoardType> boardTypes(){
    std::set<BoardType> types;
    types.insert(Classic);
    types.insert(Static);
    types.insert(Smart);
    return types;
}
bool isCorrect(BoardType t){
    static const std::set<BoardType> types = boardTypes();
    return types.count(t);
}
READ ALSO
Указатели, следующее значение

Указатели, следующее значение

Вывод значений массива, получить 4 элемента по очереди, результат

282
Имеют ли смысл указатели на ф-ции класса?

Имеют ли смысл указатели на ф-ции класса?

Недавно столкнулся с одной непонятной для меня вещью - указатели на функции классаИмеют ли они смысл ? В каких случаях используются ? Пример:

344
Помогите создать SQL запрос

Помогите создать SQL запрос

Есть 2 таблицыparam_price:

324
Как взять названия колонок из значения колонки

Как взять названия колонок из значения колонки

Как в SQL-запросе подставить в название колонки значения, которые находятся в ней?

328