C++ std::random 和枚举 class
C++ std::random and enum class
我有一个关于更现代的 C++“首选”样式的挑剔问题。
假设我想使用 std::random
的内容来 select 来自 enum class
的值。我怎样才能骗过它?我们在这里谈论一些非常基本的东西,第一个 selection 工作得很好,但是 Visual Studio 责备我(正确地)使用裸 enums
:
enum Direction:uint8_t {
Left, Right
};
std::uniform_int_distribution<uint8_t> direction(Direction::Left, Direction::Right);
// and so on...
我很惊讶基于枚举的经典作品 enum
。但是,简单地将单词 class
添加到组合中会导致整个 shebang 无法编译。
enum class Direction:uint8_t {
Left, Right
};
std::uniform_int_distribution<uint8_t> direction(Direction::Left, Direction::Right);
// Severity Code Description Project File Line Suppression State
// Error C2338 invalid template argument for uniform_int_distribution:
// N4659 29.6.1.1 [rand.req.genl]/1e requires one of short, int, long, long long, unsigned short,
// unsigned int, unsigned long, or unsigned long long
// C:\Program Files (x86)\Microsoft Visual Studio19\Enterprise\VC\Tools\MSVC.29.30133\
// include\random 1863
等等。 =)
为了解决这个问题,我当然可以放下我的骄傲和原则,但我想遵守现代标准。
如果有人想像这样洗牌 enum
时有人有一些聪明的解决方法或其他最佳实践风格的东西,我会很高兴。
enum
和 enum class
都有问题:它们不知道自己的大小,无法迭代等。作为替代,您可以使用 std::variant
和虚拟类型:
struct Left {};
struct Right {};
using Direction = std::variant<Left, Right>;
template<typename V, typename E, std::size_t idx = 0>
auto constexpr cast = [] { // written once, works for any "enum"
if constexpr (std::is_same_v<std::variant_alternative_t<idx, V>, E>) return idx;
else return cast<V, E, idx + 1>;
}();
std::uniform_int_distribution direction{cast<Direction, Left>, cast<Direction, Right>};
作为奖励,现在您可以获得“枚举”中的元素数量:
static_assert(std::variant_size_v<Direction> == 2);
你甚至可以遍历它们的枚举数:
template<typename F, typename... Es> // written once, works for any "enum"
constexpr void for_each(F f, std::variant<Es...> const&) {
(..., (void)f(Es{})); // void cast to ignore possible operator,() overloading
}
int main() {
for_each([](auto enumerator) {
std::cout << cast<Direction, decltype(enumerator)> << ' ';
}, Direction{});
}
我有一个关于更现代的 C++“首选”样式的挑剔问题。
假设我想使用 std::random
的内容来 select 来自 enum class
的值。我怎样才能骗过它?我们在这里谈论一些非常基本的东西,第一个 selection 工作得很好,但是 Visual Studio 责备我(正确地)使用裸 enums
:
enum Direction:uint8_t {
Left, Right
};
std::uniform_int_distribution<uint8_t> direction(Direction::Left, Direction::Right);
// and so on...
我很惊讶基于枚举的经典作品 enum
。但是,简单地将单词 class
添加到组合中会导致整个 shebang 无法编译。
enum class Direction:uint8_t {
Left, Right
};
std::uniform_int_distribution<uint8_t> direction(Direction::Left, Direction::Right);
// Severity Code Description Project File Line Suppression State
// Error C2338 invalid template argument for uniform_int_distribution:
// N4659 29.6.1.1 [rand.req.genl]/1e requires one of short, int, long, long long, unsigned short,
// unsigned int, unsigned long, or unsigned long long
// C:\Program Files (x86)\Microsoft Visual Studio19\Enterprise\VC\Tools\MSVC.29.30133\
// include\random 1863
等等。 =)
为了解决这个问题,我当然可以放下我的骄傲和原则,但我想遵守现代标准。
如果有人想像这样洗牌 enum
时有人有一些聪明的解决方法或其他最佳实践风格的东西,我会很高兴。
enum
和 enum class
都有问题:它们不知道自己的大小,无法迭代等。作为替代,您可以使用 std::variant
和虚拟类型:
struct Left {};
struct Right {};
using Direction = std::variant<Left, Right>;
template<typename V, typename E, std::size_t idx = 0>
auto constexpr cast = [] { // written once, works for any "enum"
if constexpr (std::is_same_v<std::variant_alternative_t<idx, V>, E>) return idx;
else return cast<V, E, idx + 1>;
}();
std::uniform_int_distribution direction{cast<Direction, Left>, cast<Direction, Right>};
作为奖励,现在您可以获得“枚举”中的元素数量:
static_assert(std::variant_size_v<Direction> == 2);
你甚至可以遍历它们的枚举数:
template<typename F, typename... Es> // written once, works for any "enum"
constexpr void for_each(F f, std::variant<Es...> const&) {
(..., (void)f(Es{})); // void cast to ignore possible operator,() overloading
}
int main() {
for_each([](auto enumerator) {
std::cout << cast<Direction, decltype(enumerator)> << ' ';
}, Direction{});
}