So the question is that some compilers throw a warning for some values that are not certainly listed among the allowed values. However, in some ITK classes they are present and hence are tested for the sake of completeness and code coverage, even if being a marginal case. When the case is included in the implementation file, it is usually expected to throw an exception.
There are several possibilities brought by @seanm in the mentioned topic:
Use the an assert(0) or __builtin_unreachable instead of throwing an exception.
enum FrustumRotationPlaneType : int
{
RotateInXZPlane = 1,
RotateInYZPlane
};
However, a scoped enum certainly seems appropriate in this particular case. If so, I think the names of the enum constants could be shortened, for example:
enum class FrustumRotationPlaneType
{
XZ = 1,
YZ
};
To be used as FrustumRotationPlaneType::XZ and FrustumRotationPlaneType::YZ.
By the way, when a function deals with each and every named enum constant of an enumerated type separately, it seems like a good idea to use a switch, instead of having multiple âifâ statements. The compiler may give a warning when the switch has accidentally forgotten to handle some of the enum constants.
I think it is fairly common to map something to the ITK enums. It may be mapping a selection from a pull down GUI to the ITK enum. Another example in SimpleITK, we redefine the enums, and them map them to the ITK enums. We have tests to verify the mapping. Also from just the SWIG interface, used in wrapping, there is another mapping from ints to enums.
The point is that the case of handling out of bounds is useful in ITK code because it is common to force-ably map ints to the enums. When an out of bounds case is encountered, it make the most since to throw an exception and let the application handle the error. Calling abort for an erroneous value will terminate the program. When interactively using ITK via Python or any other language, this may be fairly easy todo.
We need to define the desired behavior, and implement out code to meet that requirement. We should not let the C++ language dictate our behavior.
To be clear, itâs not just that âsome compilers throw a warningâ, itâs that it is not valid C++ to convert any old int into into a plain old enum. ITK currently does that in 1 or 2 places, ex:
ITK/Modules/Filtering/LabelMap/test/itkMergeLabelMapFilterTest1.cxx:82:22: runtime error: load of value 10, which is not a valid value for type âitk::MergeLabelMapFilter<itk::LabelMap<itk::LabelObject<unsigned char, 2> > >::MethodChoiceâ
Indeed, with âFixed Unscoped Enumerationsâ it is valid C++. That could be a quite backwards-compatible change for ITK to adopt, i.e. just stick " : int" after most enum definitions. That wonât change their size and would fix this particular issue. Or, leave the enums as they are, and just eliminate the 1 or 2 places where out of range values are forced in.
I do agree that this is a serious bug, that you have found, @seanm Note however, that static_cast<FrustumRotationPlaneType>(i) is OK (valid C++, no undefined behavior) for any integer i between 0 and 3 (inclusive). You see, FrustumRotationPlaneType is defined as follows: