Программа читает число с flash-памяти внешнего устройства (целое, 1 байт, беззнаковое). Для его программной интерпретации используется перечисление:
enum BoardType {
Classic = 0,
Static = 1,
Smart = 2
}
BoardType t = (BoardType)getBoardType();
Проблема видна невооружённым взглядом: число, содержащееся в памяти, не обязательно содержится в enum. И я думаю, что в runtime никак не проверить, корректно ли возвращённое число, а оно будет обязательно, ведь во flash-памяти в стёртом состоянии хранятся значения 0xFF, а также могут попадать другие числа, которые оказались там из-за моих кривых рук. Итак, есть ли способ проверить, содержится ли возвращённое число в enum, а если нет, то как правильно программно интерпретировать это число?
Я бы предложил, коль речь идет о быстродействии и небольшом количестве команд - использовать просто табличные преобразования. Да и таблица не будет чрезмерно большой.
Пример кода (ссылка на 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
будет хуже читаем, а возможно и медленнее обрабатываем.
По большому счету, никак. Потому что это просто условные обозначения для целочисленных значений.
Так что если уж очень нужно - то либо проверять диапазон (если перечисления без "просветов", либо иметь отдельное множество значений и проверять на присутствие в нем.
По-моему, так. (с) Пух
Конкретно для вашего примера можно так:
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);
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Недавно столкнулся с одной непонятной для меня вещью - указатели на функции классаИмеют ли они смысл ? В каких случаях используются ? Пример:
Как в SQL-запросе подставить в название колонки значения, которые находятся в ней?