title: How can I cleanly validate and cast to an enum that is nonsequential?
body: <p>Consider the following code:</p>
  
  <pre><code>//Note that the enum is nonsequential. I don't have control of
  //this enum so I cannot change it to be sequential
  enum class Animal {
      DOG = 0,
      CAT = 1,
      LLAMA = 20,
      ALPACA = 21,
  };
  
  //This data is received as an int,
  //but I want to know what Animal it refers to
  int data_0 = 0; 
  int data_2 = 2;
  </code></pre>
  
  <p>My application will receive some data, and I want to know which Animal it refers to.</p>
  
  <pre><code>Animal foo = static_cast&lt;Animal&gt;(data_0); //Great, it's an Animal::DOG.
  Animal bar = static_cast&lt;Animal&gt;(data_2); //Whoops!  This will crash.
  
  if (foo == Animal::DOG) { //This is an easy comparison
      //do something
  }
  </code></pre>
  
  <p>Clearly, I need to be doing some validation on the incoming data or I risk a crash.</p>
  
  <p>To me, it seems like the solution is to do explicit validation when casting an enum, but I don't know enough about C++ to know a clean way to do this:</p>
  
  <pre><code>//This is not sufficient to validate the value
  if (data_2 &gt; Animal::DOG &amp;&amp; data_2 &lt; Animal::ALPACA) {
      Animal bar = static_cast&lt;Animal&gt;(data_2); //Whoops!  This will crash.
  }
  
  //This is sufficient to validate the value, but is very ugly
  Animal bar;
  if (data_2 == static_cast&lt;int&gt;(Animal::DOG)   ||
      data_2 == static_cast&lt;int&gt;(Animal::CAT)   ||
      data_2 == static_cast&lt;int&gt;(Animal::LLAMA) ||
      data_2 == static_cast&lt;int&gt;(Animal::ALPACA)) {
      bar = static_cast&lt;Animal&gt;(data_2); //This does not run because of the checking
  }
  
  //bar was not assigned, so it would be NULL or 0
  if (bar == Animal::DOG) {
      //oh no, we shouldn't be here!
  }
  </code></pre>
  
  <p>There has to be a better way to do this, so I feel like I'm missing something.  How could I designthis be done such that an int can be cast to an Animal, but Animal cannot end up being an invalid value when the casting fails?</p>