Good day. The situation is the following, a packet comes from the server, in a certain field of which there is a byte that I want to transfer to the method as a member of a certain enum. To cast, I use a static caste, but I wondered what would happen if the server sends me incorrect data and the value in this byte is outside of enum. I threw in the test code and, as it turned out, C ++ calmly swallows it and there is nothing to throw (.

enum class MyEnum { Red = 1, Black = 2, White = 3 }; void Foo(MyEnum val) { std::cout << static_cast<int>(val) << std::endl; }; int main() { Foo(MyEnum::Red); Foo(static_cast<MyEnum>(3)); Foo(static_cast<MyEnum>(5)); system("PAUSE"); return 0; } 

Are there any standard tools to effectively (in terms of performance) check the entry of a value into a specific enum and give me the opportunity to throw an exception. If they are not, then how to do it, not shoveling the entire enum with his hands. And is it possible to do something like foreach enuma bypassing a garden (something like for (auto i: MyEnum) ...)?

ps C ++ 14 compiler GCC 6.3.

  • switch from the default in terms of speed will be "instant", there is nothing to worry about, but in terms of writing for several enum `s with a set of values, alas and oh. - ffk
  • Enums are not intended for such a purpose. - avp

3 answers 3

I'm here for you something I do not know how much help. After adding in the enumeration, you will have to add to the ++ operator

 #include <iostream> #include <bitset> 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; } 

Well, you can do all this in some kind of function, or based on this create a class - an iterator. Here index will matter as an index in vectors ...

  • Thank you very much. But you have to add a new member enum should be accompanied by the addition of a new member outside of it (I wrote about it in another answer). I definitely should not have this. After three months, adding a new member to enum, I will definitely forget to add it to the overload function even if I write about it in caps in comments. And other people working with my class will not thank me. When you need to change some parameter of the system, then I have to change it in one, only place. If this is not the case, then I always start with big problems and result in many hours of debugging. - mrFieldy
  • @mrFieldy, after 3 months your transfer must be stored somewhere in the program, and the operator is stored there. Keep them in some namespace, then you will not forget. No other decisions occurred to me - AR Hovsepyan
 #include <iostream> enum class MyEnum { Unknown = 0, Red = 1, Black = 2, White = 3, // новые значения вписывать сюда Max }; void Foo(MyEnum val) { std::cout << static_cast<int>(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<MyEnum>(3)) << std::endl; std::cout << checkEnum(static_cast<MyEnum>(5)) << std::endl; return 0; } 

The output will be:

 true true false 

The truth here is one restriction, Red, Black, White - must be values ​​in order, you can not write:

 enum class MyEnum { Unknown = 0, Red = 1, Black = 3, White = 6, // новые значения вписывать сюда Max }; 

If the values ​​do not go in order, then this option is possible, though here after adding the value to enum, you need to add the value to set

 #include <iostream> #include <vector> #include <set> enum class MyEnum { Red = 1, Black = 3, White = 6, }; static std::set<MyEnum> 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<MyEnum>(3)) << " " << checkEnum(static_cast<MyEnum>(5)); return 0; } 
  • one
    Unfortunately, the values ​​can not go in order, and this enum will be expanded all the time. But thank you very much for the idea of ​​how to do this with persistent enums. - mrFieldy
  • @mrFieldy, completed the answer. - Alexander
  • About these gardens and I say. I would not want to fence them. All these changes should occur in one place and spread to the whole code. I guarantee you that after 3 months of adding new values ​​to the enum, I will definitely forget to add the value to the set. But if there is no other way out, then you will have to build something like that. - mrFieldy
  • @mrFieldy, enum's are not intended for what you want to do with them, because you have to make some kind of garden, most likely using macros. Although if you had Qt, then his Q_ENUM would most likely solve your problems. - Alexander

Enum-types in C ++ ensure the representability of any integer values ​​in the range from 0 to 2^n , where n is the minimum number of bits necessary to represent explicitly declared enum members. (The rigorous formulation is more complicated, but the idea is just that.) There is nothing illegal in writing to enum-objects of values ​​from this range using explicit type conversion, even if the recorded value does not match any of the names.

There are no means for enum elements in the language. Yes, and they can not be, because no one guaranteed the unambiguous correspondence of the enum elements with integer values. You can even assign all of them the same value.

 enum class MyEnum { Red = 1, Black = 1, White = 1 }; 

There is nothing illegal about it.

In other words, the enum-type covers a whole range of integer values, and only some of the values ​​of this range are named (possibly multiple times). You can only check the value manually by name, i.e. in the simplest case, a direct comparison with the named values.

  • But the question is different. I understand that this is very flexible, but I need to write a secure application. When I receive a value that is not in enum, I need to throw an exception. How do I do this better? The task, I think, is quite typical. - mrFieldy
  • @mrFieldy, exactly what “seems” :) - isnullxbh
  • @mrFieldy, you manually give the names to the bits, and you will have to manually check. Another question is where and how will you do it - AR Hovsepyan
  • @ARHovsepyan why do you manually add identically manual check or bypass? In C #, let's say I would easily implement it. I wonder why in C ++ and in std such a poor functionality for working with enums. Why in std it was impossible to implement any function to create an iterator on enum (I understand that enum is a type). - mrFieldy
  • @ mrFieldy, I didn’t say that it was a joke - sometimes joking is also useful ... But I’ll note your question as useful because it intrigued me to think about it. In life, almost nothing is impossible, there are only those who do not succeed, and C ++ is the language of "life". - AR Hovsepyan