c++ - Detecting if casting an int to an enum results into a non-enumerated value -
let's have :
enum cardcolor { hearts, diamonds, clubs, spades}; cardcolor mycolor = static_cast<cardcolor>(100);
is there (simple) way detect, either @ compile-time or @ runtime, value of mycolor
doesn't correspond enumerated value ?
and more generally, if enum values not following each other, instance :
enum cardcolor { hearts = 0, diamonds, clubs = 4, spades};
cashcow presents a decent answer question: it's straightforward write custom function perform checked cast.
unfortunately, it's lot of work , must make sure keep synchronized enumeration list of enumerators in enumeration definition same list of enumerators in checked cast function. have write 1 of these each enumeration want able perform checked cast.
instead of doing manual work, can automate generation of of code using preprocessor (with little boost preprocessor library). here macro generates enumeration definition along checked_enum_cast
function. it's bit scary looking (code generation macros horrible upon), it's extremely useful technique become familiar with.
#include <stdexcept> #include <boost/preprocessor.hpp> // internal helper provide partial specialization checked_enum_cast template <typename target, typename source> struct checked_enum_cast_impl; // exception thrown checked_enum_cast on cast failure struct invalid_enum_cast : std::out_of_range { invalid_enum_cast(const char* s) : std::out_of_range(s) { } }; // checked cast function template <typename target, typename source> target checked_enum_cast(source s) { return checked_enum_cast_impl<target, source>::do_cast(s); } // internal helper declare case labels in checked cast function #define x_define_safe_cast_case(r, data, elem) case elem: // macro define enum checked cast function. name name of // enumeration defined , enumerators preprocessing sequence // of enumerators defined. see usage example below. #define define_safe_cast_enum(name, enumerators) \ enum name \ { \ boost_pp_seq_enum(enumerators) \ }; \ \ template <typename source> \ struct checked_enum_cast_impl<name, source> \ { \ static name do_cast(source s) \ { \ switch (s) \ { \ boost_pp_seq_for_each(x_define_safe_cast_case, 0, enumerators) \ return static_cast<name>(s); \ default: \ throw invalid_enum_cast(boost_pp_stringize(name)); \ } \ return name(); \ } \ };
here how use cardcolor
example:
define_safe_cast_enum(cardcolor, (hearts) (clubs) (spades) (diamonds)) int main() { checked_enum_cast<cardcolor>(1); // ok checked_enum_cast<cardcolor>(400); // o noez! exception! }
the first line replaces enum cardcolor ...
definition; defines enumeration , provides specialization allows use checked_enum_cast
cast integers cardcolor
.
this may lot of hassle checked cast function enums, technique useful , extensible. can add functions sorts of things. example, have 1 generates functions convert enumerated types , string representations , functions perform several other conversions , checks use of enumerations.
remember, have write , debug big, ugly macro once, can use everywhere.
Comments
Post a Comment