Страницы

Поиск по вопросам

воскресенье, 9 февраля 2020 г.

Правильная проверка обычной переменной на вхождение в enum.

#cpp #enum #cpp14


Доброго времени суток. Ситуация следующая, с сервера приходит пакет, в определённом
поле которого есть байт, который я хочу передавать в метод как член определённого enum’а.
Для приведения я использую статик каст, но я задумался о том, что будет, если сервер
пришлёт мне некорректные данные и значение в этом байте окажется за пределами enum’а.
Накидал тестовый код и как оказалось С++ спокойно это проглотит и не чего не бросит (.

enum class MyEnum {
    Red = 1,
    Black = 2,
    White = 3
};
void Foo(MyEnum val) {
    std::cout << static_cast(val) << std::endl;
};

int main()
{
    Foo(MyEnum::Red);
    Foo(static_cast(3));
    Foo(static_cast(5));
    system("PAUSE");
    return 0;
}


Есть ли какие-то стандартные средства эффективно (с точки зрения производительности)
проверить вхождение значения в конкретный enum и дать мне возможность бросит исключение.
Если их нет, то как это сделать, не перелопачивая весь enum руками. И можно ли как
то сделать foreach обход enuma не городя огород (что то типа for (auto i : MyEnum) ...)?

p.s. С++ 14 компилятор GCC 6.3. 
    


Ответы

Ответ 1



Я тут для вас кое что сооброзил, не знаю насколько поможет. Вам придется просто после добавления в перечислении, добавлять и в оператор ++ #include #include using namespace std; enum class Some { min, s1 = 3, s2 = 5, s3 = 7, max = 9, end = 100 }; Some& operator++(Some& s) { switch(s) { case Some::min: return s = Some::s1; case Some::s1: return s = Some::s2; case Some::s2: return s = Some::s3; case Some::s3: return s = Some::max; case Some::max: s = Some::end; } return s; } int main() { int n = 5, index; Some t = Some::min; while (int(t) != n && t != Some::end) { ++t; ++index; } if (t == Some::end) cout << "indefined" ; else cout << index; // выдаст 2 return 0; } Ну можно это все проделать в какой то функции, или на основе этого создавать класс - итератор. Тут index будет иметь значение как индекс в векторах...

Ответ 2



#include enum class MyEnum { Unknown = 0, Red = 1, Black = 2, White = 3, // новые значения вписывать сюда Max }; void Foo(MyEnum val) { std::cout << static_cast(val) << std::endl; } bool checkEnum(MyEnum _val) { return _val > MyEnum::Unknown && _val < MyEnum::Max; } int main() { std::cout << checkEnum(MyEnum::Red) << std::endl; std::cout << checkEnum(static_cast(3)) << std::endl; std::cout << checkEnum(static_cast(5)) << std::endl; return 0; } Вывод будет: true true false Правда тут одно ограничение, Red, Black, White - должны быть значениями по порядку, нельзя писать: enum class MyEnum { Unknown = 0, Red = 1, Black = 3, White = 6, // новые значения вписывать сюда Max }; Если же значения не идут по порядку, то возможен такой вариант, правда тут после добавления значения в enum, нужно добавить значение и в set #include #include #include enum class MyEnum { Red = 1, Black = 3, White = 6, }; static std::set enumArr{ MyEnum::Red, MyEnum::Black, MyEnum::White }; bool checkEnum(MyEnum _val) { return enumArr.find(_val) != enumArr.end(); } int main() { std::cout << std::boolalpha << checkEnum(MyEnum::Red) << " " << checkEnum(static_cast(3)) << " " << checkEnum(static_cast(5)); return 0; }

Ответ 3



Enum-типы в С++ гарантируют представимость любых целочисленных значений в диапазоне от 0 до 2^n, где n - минимальное количество битов необходимое для представления явно объявленных членов enum. (Строгая формулировка более сложна, но идея именно такая.) Нет ничего нелегального в записи в enum-объекты значений из этого диапазона при помощи явного приведения типа, даже если записываемое значение не совпадает ни с одним из поименованных. Средств перечисления элементов enum в языке нет. Да и не может их быть, ибо никто не гарантировал однозначного соответствия элементов enum целочисленным значениям. Можно хоть всем им назначить одно и то же значение enum class MyEnum { Red = 1, Black = 1, White = 1 }; Ничего нелегального в этом нет. Другими словами enum-тип покрывает целый диапазон целочисленных значений, и лишь некоторые из значений этого диапазона поименованы (возможно многократно). Проверить значение на поименованность можно только вручную, т.е. в простейшем случае прямым сравнением с именованными значениями.

Комментариев нет:

Отправить комментарий