Bar*_*art 17 c++ c++11 c++14 c++17 c++20
如果枚举是连续的,有没有办法在 C++11 中检查?
给出不是的枚举值是完全有效的。是否有像 C++14、C++17 或 C++20 中的类型特征这样的特性来检查枚举是否连续?这将在 static_assert 中使用。
一个小例子如下:
enum class Types_Discontinuous {
A = 10,
B = 1,
C = 100
};
enum class Types_Continuous {
A = 0,
B = 1,
C = 2
};
static_assert(SOME_TEST<Types_Discontinuous>::value, "Enum should be continuous"); // Fails
static_assert(SOME_TEST<Types_Continuous>::value, "Enum should be continuous"); // Passes
Run Code Online (Sandbox Code Playgroud)
这在纯 C++ 中是不可能的,因为无法枚举枚举值,或发现值的数量以及最小值和最大值。但是您可以尝试使用编译器的帮助来实现接近您想要的东西。例如,在 gcc 中,如果switch语句不处理枚举的所有值,则可能会强制执行编译错误:
enum class my_enum {
A = 0,
B = 1,
C = 2
};
#pragma GCC diagnostic push
#if __GNUC__ < 5
#pragma GCC diagnostic error "-Wswitch"
#else
#pragma GCC diagnostic error "-Wswitch-enum"
#endif
constexpr bool is_my_enum_continuous(my_enum t = my_enum())
{
// Check that we know all enum values. Effectively works as a static assert.
switch (t)
{
// Intentionally no default case.
// The compiler will give an error if not all enum values are listed below.
case my_enum::A:
case my_enum::B:
case my_enum::C:
break;
}
// Check that the enum is continuous
auto [min, max] = std::minmax({my_enum::A, my_enum::B, my_enum::C});
return static_cast< int >(min) == 0 && static_cast< int >(max) == 2;
}
#pragma GCC diagnostic pop
Run Code Online (Sandbox Code Playgroud)
显然,这是专门针对给定的枚举,但可以使用预处理器自动定义此类函数。
对于许多enums,您可能可以使用Magic Enum库来解决这个问题。例如:
#include "magic_enum.hpp"
template <typename Enum>
constexpr bool is_continuous(Enum = Enum{}) {
// make sure we're actually testing an enum
if constexpr (!std::is_enum_v<Enum>)
return false;
else {
// get a sorted list of values in the enum
const auto values = magic_enum::enum_values<Enum>();
if (std::size(values) == 0)
return true;
// for every value, either it's the same as the last one or it's one larger
auto prev = values[0];
for (auto x : values) {
auto next = static_cast<Enum>(magic_enum::enum_integer(prev) + 1);
if (x != prev && x != next)
return false;
else
prev = x;
}
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,正如库名所暗示的那样,这确实是“魔术”——库函数在许多特定于编译器的黑客中。因此,它并不能真正满足您对“纯 C++”的要求,但在语言中具有反射功能之前,它可能与我们所能达到的一样好。