这在表面上可能过于复杂,但它很好地概括了模板 voodoo 可以隐藏在远离视线的标题中。
#include <stdexcept>
template <class TYPE>
TYPE do_conversion(int value)
{
if (value >= static_cast<int>(TYPE::First) &&
value < static_cast<int>(TYPE::Last))
{
return static_cast<TYPE>(value);
}
throw std::out_of_range("Inv value");
}
所有的转换都被转移到一个函数中以降低噪音。
有效范围使用额外的枚举值First and Last 进行抽象。如果给定值在范围内(First,Last],则分配该值。如果不是,则抛出异常。根据无效输入的频率,异常可能不是正确的做法,如果错误的输入很常见,但在这里它有助于使示例保持简单。
现在调用很简单
enum class Weekday
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
Last, // added
First = Monday // added
};
以后
Weekday day = do_conversion<Weekday>(value);
转换产生的所有噪音都不会影响转换所需的任何内容,因此读取或编写该段代码的任何人都可以继续他们的工作。
但是如果你在没有First 和Last 的enum 上使用它呢?编译器消息可能会变得奇怪,因此最好帮助用户一点。以下内容已从How to detect whether there is a specific member variable in class? 中掠夺,以使其更易于使用。绝对花时间阅读答案以了解发生了什么。我还没有想出一个体面的方法来结合HasFirst 和HasLast。请发表评论,如果你有,请告诉我。
#include <stdexcept>
#include <type_traits>
template <typename T, typename = int>
struct HasFirst : std::false_type { };
template <typename T>
struct HasFirst <T, decltype((void) T::First, 0)> : std::true_type { };
template <typename T, typename = int>
struct HasLast : std::false_type { };
template <typename T>
struct HasLast <T, decltype((void) T::Last, 0)> : std::true_type { };
template <class TYPE>
TYPE do_conversion(int value)
{
static_assert(HasFirst<TYPE>::value, "enum missing First");
static_assert(HasLast<TYPE>::value, "enum missing Last");
if (value >= static_cast<int>(TYPE::First) &&
value < static_cast<int>(TYPE::Last))
{
return static_cast<TYPE>(value);
}
throw std::out_of_range("Inv value");
}
现在,如果 enum 缺少最重要的元值,编译器可以通过简单的错误消息告诉它们。
Test case