C++ std::random and enum class



我有一个关于更现代的c++的棘手问题"首选"风格。

假设我想使用std::random的内容来从enum class中选择一个值。我怎么骗得了?我们在这里讨论的是一些非常基本的东西,其中第一个选择工作得很好,但是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添加到组合中会导致整个组合无法编译。

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 Studio2019EnterpriseVCToolsMSVC14.29.30133
//    includerandom    1863    

以此类推。=)

为了解决这个问题,我当然可以放弃我的自尊和原则,但我想遵守现代的标准。

如果有人有一些聪明的解决方法或其他最佳实践风格的东西,当一个人想要洗牌enum像这样,我会很高兴粉红色。

enumenum 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{});
}

最新更新