CashCow将a decent answer提交给这个问题:编写一个自定义函数来执行一个checked cast是很简单的。
不幸的是,这也是很多工作,您必须确保它与枚举同步,以便枚举定义中的枚举器列表与checked函数中的枚举器列表相同。您还必须为每个您希望能够执行checked cast的枚举编写其中的一个。
不用做所有这些手动工作,我们可以使用预处理器(通过Boost预处理器库的一些帮助)自动生成所有这些代码。这里是一个宏,它产生一个枚举定义以及一个checked_enum_cast
函数。看起来可能有些可怕(代码生成宏往往是可怕的),但这是一个非常有用的技术,可以熟悉。
#include <stdexcept>
#include <boost/preprocessor.hpp>
// Internal helper to provide partial specialization for checked_enum_cast
template <typename Target, typename Source>
struct checked_enum_cast_impl;
// Exception thrown by 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 to help declare case labels in the checked cast function
#define X_DEFINE_SAFE_CAST_CASE(r, data, elem) case elem:
// Macro to define an enum with a checked cast function. name is the name of
// the enumeration to be defined and enumerators is the preprocessing sequence
// of enumerators to be defined. See the 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(); \
} \
};
这里是你将如何使用您的CardColor
例如:
DEFINE_SAFE_CAST_ENUM(CardColor, (HEARTS) (CLUBS) (SPADES) (DIAMONDS))
int main()
{
checked_enum_cast<CardColor>(1); // ok
checked_enum_cast<CardColor>(400); // o noez! an exception!
}
第一行替换您enum CardColor ...
定义;它定义枚举并提供专门化,使您可以使用checked_enum_cast
将整数转换为CardColor
。
这可能看起来像很多麻烦只是为您的枚举获得一个checked cast函数,但这种技术是非常有用和可扩展的。你可以添加各种各样的功能。例如,我有一个生成函数来将枚举类型转换为字符串表示和函数,这些字符串表示和函数执行其他几次转换并检查我用于大多数枚举的函数。请记住,你必须编写和调试那个大的,丑陋的宏只是一次,然后你可以在任何地方使用它。
在运行时还是编译时? – CashCow 2011-01-25 16:24:25
除“不这样做”? – 2011-01-25 16:24:56
@CashCow:恩,都!我更新了我的问题。 – 2011-01-25 16:26:42