2

Suppose i have an enum class

   enum class Sectors {
     A = 1, B, C, D, E, F, G, H
   };

I need to read data from file to assign numeric data to variable of Sectors type. I use this template function to convert from integer to enumeration value.

   template <typename Enumeration, typename NumType> 
   Enumeration NumericToEnum(NumType const value) {
     return static_cast<Enumeration>(value);
   };

Is there a way to check whether given numeric value is actually in given enumeration range?

   Sectors sec1 = NumericToEnum<Sectors>(intValueFromFile); //ok when 2
   Sectors sec2 = NumericToEnum<Sectors>(999); //error, out of range

I know how to to check before passing to function (value >= Sectors::A && value <= Sectors::H ), but i would preferably do it inside template function and maybe throw exception. Is it possible?

Cody Gray
  • 222,280
  • 47
  • 466
  • 543
  • 2
    This question gets asked reasonably often. To my knowledge, there is no built-in solution for determining whether an arbitrary integer is within the range of a particular array. You could code up your own, but it non-trivial. It would either require that you specialize it for every enum, or add sentinel values to all of your enums. And even then, you have to bear in mind that enums do not require that all their members have sequential integer IDs. – Cody Gray Dec 02 '16 at 15:58
  • 1
    enums is a way of defining constants. Named enums is a way of using some constants inside the scope of the name. A good reason to use enums is to avoid "wild" values in some function, allowing only the defined in the enumeration. Playing with converting an integer to an enum is not a good design. Apart from obfuscating the code, it's prone to mistakes. – Ripi2 Dec 02 '16 at 16:05
  • @Ripi2 I agree that it is not good design, but if you want to store a struct with an integer value on a field and later read it from the file you get this problem. An alternative question would be: can you create an enumeration value by reading it from a file - and ensure it is in range, even if the file is corrupted. http://stackoverflow.com/questions/5633784/input-from-stream-to-enum-type – Hans Olsson Dec 02 '16 at 16:18
  • @Ripi2 What would be an alternative if I wanted to use a variable of a type that can hold only certain pre-defined values? I find it very convenient and beautiful to overload some operators for enums and then do things like `for(Sectors s = Sector::A; s <= Sectors::H; s++) {}`. Do i have to go back to "everything is unsigned int"? – waitNotDone Dec 02 '16 at 16:20
  • What you may find "convenient and beautiful" I would find it a way of abusing C++. If you want something that throws an exception when no enum value is matched, well, make a class for it; enums are not needed then, just a private vector with valid (perhaps not consecutive) values. – Ripi2 Dec 02 '16 at 23:33

1 Answers1

0

You can define additional enum values that specify the range:

enum class Sectors {
     A = 1, B, C, D, E, F, G, H,
     SEC_MIN = A, SEC_MAX = H
};

and check using a assert:

template <typename Enumeration, typename NumType> 
Enumeration NumericToEnum(NumType const value) {
    assert((value >= Enumeration::SEC_MIN && value <= Enumeration::SEC_MAX),"value must be in valid range");
    return static_cast<Enumeration>(value);
};
πάντα ῥεῖ
  • 83,259
  • 13
  • 96
  • 175