C++: loading out-of-range values to enums without fixed underlying type is undefined behavior
When I run the [test suite](https://github.com/kaitai-io/kaitai_struct_tests) with [Clang's **UndefinedBehaviorSanitizer**](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html), I get the following errors:

<pre><code>/mnt/c/temp/kaitai_struct/tests/compiled/cpp_stl_98/enum_for_unknown_id.h:38:35: <b>runtime error:</b> load of value 80, which is not a valid value for type 'enum_for_unknown_id_t::animal_t'
/mnt/c/temp/kaitai_struct/tests/compiled/cpp_stl_98/switch_manual_enum_invalid.h:109:43: <b>runtime error:</b> load of value 255, which is not a valid value for type 'switch_manual_enum_invalid_t::opcode_t::code_enum_t'
/mnt/c/temp/kaitai_struct/tests/compiled/cpp_stl_98/switch_manual_enum_invalid_else.h:133:43: <b>runtime error:</b> load of value 255, which is not a valid value for type 'switch_manual_enum_invalid_else_t::opcode_t::code_enum_t'</code></pre>

This can be confirmed on https://en.cppreference.com/w/cpp/language/enum#Notes:

> ### Notes
> Although the conversion from an out-of-range to an enumeration without fixed underlying type is made undefined behavior by the resolution of [CWG issue 1766](https://cplusplus.github.io/CWG/issues/1766.html), currently no compiler performs the required diagnostic for it in constant evaluation.

... and https://wiki.sei.cmu.edu/confluence/display/cplusplus/INT50-CPP.+Do+not+cast+to+an+out-of-range+enumeration+value:

> The C++ Standard, [expr.static.cast], paragraph 10, states the following:
> 
> > (...) If the enumeration type has a fixed underlying type, the value is first converted to that type by integral conversion, if necessary, and then to the enumeration type. If the enumeration type **does not have a fixed underlying type**, the value is unchanged if the original value is within the range of the enumeration values (_9.7.1_), and otherwise, the **behavior is undefined**.

There are also compliant solutions on the [last mentioned page](https://wiki.sei.cmu.edu/confluence/display/cplusplus/INT50-CPP.+Do+not+cast+to+an+out-of-range+enumeration+value):

> ## Compliant Solution (Scoped Enumeration)
> 
> This compliant solution uses a scoped enumeration, which has a fixed underlying `int` type by default, allowing any value from the parameter to be converted into a valid enumeration value. It does not restrict the converted value to one for which there is a specific enumerator value, but it could do so as shown in the previous compliant solution.
> 
> ```cpp
> enum class EnumType {
>   First,
>   Second,
>   Third
> };
>  
> void f(int intVar) {
>   EnumType enumVar = static_cast<EnumType>(intVar);
> }
> ```
> 
> ## Compliant Solution (Fixed Unscoped Enumeration)
> 
> Similar to the previous compliant solution, this compliant solution uses an unscoped enumeration but provides a fixed underlying `int` type allowing any value from the parameter to be converted to a valid enumeration value.
> 
> ```cpp
> enum EnumType : int {
>   First,
>   Second,
>   Third
> };
>  
> void f(int intVar) {
>   EnumType enumVar = static_cast<EnumType>(intVar);
> }
> ```
> 
> Although similar to the previous compliant solution, this compliant solution differs from the noncompliant code example in the way the enumerator values are expressed in code and which implicit conversions are allowed. The previous compliant solution requires a nested name specifier to identify the enumerator (for example, `EnumType::First`) and will not implicitly convert the enumerator value to `int`. As with the noncompliant code example, this compliant solution does not allow a nested name specifier and will implicitly convert the enumerator value to `int`.

Both these solutions are only available since C++11, though, so there is probably no solution for C++98. But I guess it's OK that C++98 just doesn't solve everything optimally, because it's not possible due to missing features.

For C++11 and newer, I would be more inclined towards scoped enums because of the following traits, which may break backward compatibility (and require some changes to the code generation), but I think are generally desirable:

> The previous compliant solution (_note: the one using scoped enum_) requires a nested name specifier to identify the enumerator (for example, `EnumType::First`) and will not implicitly convert the enumerator value to `int`. 