C++ 不是 Java!每种语言都有自己的技术,这些技术非常适合该语言。不要试图用另一种语言在相同(但被破坏的)结构中模仿一种语言的完美结构。
以下是我将如何在 C++ 中解决您的问题:
// Define the actual enumeration
enum class [[nodiscard]] Vehicle : unsigned char
{
CAR,
MOTORCYCLE,
SIZE [[maybe_unused]]
};
// Convert your enumeration to a string (view)
#include <cassert>
#include <string_view>
[[nodiscard]] constexpr auto to_string(Vehicle v) noexcept -> std::string_view {
assert(v != Vehicle::SIZE);
switch (v) {
case Vehicle::CAR:
return "Car";
case Vehicle::MOTORCYCLE:
return "Motorcycle";
}
}
要使用它,您可以执行以下操作:
for (unsigned char c = 0; c < static_cast<unsigned char>(Vehicle::SIZE); ++c)
std::cout << to_string(static_cast<Vehicle>(c)) << std::endl;
每次都编写这个有点麻烦,但是,您可以编写自己的模板类来帮助对其进行迭代。例如:
#include <type_traits>
// The generic stuff you only write once
// Assumes you don't assign any values to your enumeration by hand + it ends on
// 'SIZE' (unless a second argument was passed if a different name was used)
template <typename TEnumeration, TEnumeration TSize = TEnumeration::SIZE>
class [[nodiscard]] EnumRange final {
using type = std::underlying_type_t<TEnumeration>;
public:
// The iterator that can be used to loop through all values
//
class [[nodiscard]] Iterator final {
TEnumeration value{static_cast<TEnumeration>(0)};
public:
constexpr Iterator() noexcept = default;
constexpr Iterator(TEnumeration e) noexcept : value{e} {}
constexpr auto operator*() const noexcept -> TEnumeration { return value; }
constexpr auto operator-> () const & noexcept -> const TEnumeration* {
return &value;
}
constexpr auto operator++() & noexcept -> Iterator {
value = static_cast<TEnumeration>(1 + static_cast<type>(value));
return *this;
}
[[nodiscard]] constexpr auto operator==(Iterator i) -> bool { return i.value == value; }
[[nodiscard]] constexpr auto operator!=(Iterator i) -> bool { return i.value != value; }
};
constexpr auto begin() const noexcept -> Iterator { return Iterator{}; }
constexpr auto cbegin() const noexcept -> Iterator { return Iterator{}; }
constexpr auto end() const noexcept -> Iterator { return Iterator{TSize}; }
constexpr auto cend() const noexcept -> Iterator { return Iterator{TSize}; }
[[nodiscard]] constexpr auto size() const noexcept -> type {
return static_cast<type>(TSize);
}
};
用法:
#include <iostream>
int main(int, char**) {
auto range = EnumRange<Vehicle>{};
std::cout << static_cast<int>(range.size()) << std::endl;
for (auto v : range) std::cout << to_string(v) << std::endl;
}
正如您在第一个测试代码中看到的,您可以使用static_cast 从数值转换为枚举。但是,它假定您有一些对枚举有效的值。使用相同的范围假设,我们可以编写自己的检查变量:
#include <stdexcept>
#include <type_traits>
template <typename TEnumeration, TEnumeration TSize = TEnumeration::SIZE>
[[nodiscard]] constexpr auto checked_enum_cast(
std::underlying_type_t<TEnumeration> numeric_value) noexcept(false)
-> TEnumeration {
using type = std::underlying_type_t<TEnumeration>;
if constexpr (std::is_signed_v<type>)
if (numeric_value < 0) throw std::out_of_range{"Negative value"};
if (numeric_value >= static_cast<type>(TSize)) throw std::out_of_range{"Value too large"};
return static_cast<TEnumeration>(numeric_value);
}
要使用这个,你可以写:
try {
std::cout << to_string(checked_enum_cast<Vehicle>(1)) << std::endl;
std::cout << to_string(checked_enum_cast<Vehicle>(2)) << std::endl;
} catch (const std::out_of_range& e) {
std::cout << e.what() << std::endl;
}
注意:如果要生活在一个没有异常的世界中,可以返回 std::nullopt 并将返回类型改为 std::optional<TEnumeration>。
All code combined + execution at Compiler Explorer
请注意,迭代器可以精炼,但是,我不是细节方面的专家。 (对于循环,没关系,如果你想将它用于算法,它可以)