如何限制从 int 到 enum class 的转换?
How to restrict conversion from int to enum class?
如果我有这样的enum class
:
enum class Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
我有一个从 int
到 Weekday
的转换:
Weekday day = static_cast<int>(value);
要检查为转换提供的值是否有效,我应该有代码:
if (value != 0 && value != 1 && value !=2 && value !=3 && value != 4 && value != 5 && value != 6) {
do_conversion(value);
}
太丑了。有什么好的方法吗?
枚举的默认基础类型 class 是整数。因此,要检查一个整数是否在可接受的枚举值范围内,您可以使用 static_cast<int>
:
将其与可接受的枚举值的范围进行比较
if (value >= static_cast<int>(Weekday::Monday) && value <= static_cast<int>(Weekday::Sunday))
{
do_conversion(value);
}
这可能是 over-complicating 表面上的东西,但它概括得很好,模板巫术可以隐藏在 header 远离视线的地方。
#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
缺少 all-important 元值,编译器可以通过简单的错误消息告诉它们。
如果我有这样的enum class
:
enum class Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
我有一个从 int
到 Weekday
的转换:
Weekday day = static_cast<int>(value);
要检查为转换提供的值是否有效,我应该有代码:
if (value != 0 && value != 1 && value !=2 && value !=3 && value != 4 && value != 5 && value != 6) {
do_conversion(value);
}
太丑了。有什么好的方法吗?
枚举的默认基础类型 class 是整数。因此,要检查一个整数是否在可接受的枚举值范围内,您可以使用 static_cast<int>
:
if (value >= static_cast<int>(Weekday::Monday) && value <= static_cast<int>(Weekday::Sunday))
{
do_conversion(value);
}
这可能是 over-complicating 表面上的东西,但它概括得很好,模板巫术可以隐藏在 header 远离视线的地方。
#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
缺少 all-important 元值,编译器可以通过简单的错误消息告诉它们。