CashCow 向这个问题提出a decent answer:编写自定义函数来执行检查强制转换当然很简单。
不幸的是,这也是很多工作,您必须确保它与枚举保持同步,以便枚举定义中的枚举数列表与检查强制转换函数中的枚举数列表相同。您还必须为您希望能够对其执行检查强制转换的每个枚举编写其中一个。
我们可以使用预处理器(在 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。
这可能看起来很麻烦,只是为您的枚举获取一个检查的强制转换函数,但这种技术非常有用且可扩展。您可以添加执行各种操作的函数。例如,我有一个生成函数来将枚举类型转换为字符串表示和执行其他几种转换和检查的函数,这些函数用于我的大多数枚举。
记住,你必须编写和调试那个又大又丑的宏一次,然后你就可以在任何地方使用它。