提问人:digito_evo 提问时间:1/26/2022 最后编辑:digito_evo 更新时间:1/27/2022 访问量:315
如何遍历枚举类的枚举器?
How to iterate over enumerators of an enum class?
问:
有没有办法用 的枚举器初始化容器(例如 )?std::unordered_set<char>
enum class
我有这个班级:
#include <iostream>
#include <unordered_set>
class Foo
{
public:
inline static const std::unordered_set<char> chars_for_drawing { '/', '\\', '|', '-' };
};
int main( )
{
for ( const char ch : Foo::chars_for_drawing )
{
std::cout << ch << ' ';
}
}
但是我希望使用枚举器初始化该集合:chars_for_drawing
#include <iostream>
#include <unordered_set>
class Foo
{
public:
enum class AllowedChars : char
{
ForwardSlash = '/',
BackSlash = '\\',
VerticalSlash = '|',
Dash = '-'
};
// inline static const std::unordered_set<char> chars_for_drawing { '/', '\\', '|', '-' }; // not like this
inline static const std::unordered_set<char> chars_for_drawing {
static_cast<char>( AllowedChars::ForwardSlash ),
static_cast<char>( AllowedChars::BackSlash ),
static_cast<char>( AllowedChars::VerticalSlash ),
static_cast<char>( AllowedChars::Dash )
};
};
int main( )
{
for ( const char ch : Foo::chars_for_drawing )
{
std::cout << ch << ' ';
}
}
可以看出,第二种方法有点混乱。有没有办法遍历枚举器并将它们分配给 ?也许通过使用 lambda?unordered_set
答:
1赞
463035818_is_not_an_ai
1/26/2022
#1
不,没有直接的方法。人们经常忘记的一点是:枚举值的范围由其基础类型决定。枚举器只是一些命名的常量。你的枚举:
enum class AllowedChars : char
{
ForwardSlash = '/',
BackSlash = '\\',
VerticalSlash = '|',
Dash = '-'
};
有助于迭代多达
struct {
char value;
static const char ForwardSlash = '/';
static const char BackSlash = '\\';
static const char VerticalSlash = '|';
static const char Dash = '-';
};
does:一点也不。
当枚举器具有连续值时,情况就不同了,有时使用的技巧是使用特殊的枚举器来表示“大小”:
enum class AllowedChars : char
{
ForwardSlash,
BackSlash,
VerticalSlash,
Dash,
SIZE
};
int main() {
for (int i=0;i< static_cast<int>(AllowedChars::SIZE); ++i){
std::cout << i;
}
}
仅此一项就有点傻,因为与实际角色的映射丢失了。但是,它可以由数组提供:
#include <iostream>
enum class AllowedCharNames : char
{
ForwardSlash,
BackSlash,
VerticalSlash,
Dash,
SIZE
};
char AllowedChars[] = {'/','\\','|','-'};
int main() {
std::cout << AllowedChars[static_cast<size_t>(AllowedCharNames::Dash)];
for (int i=0;i< static_cast<int>(AllowedCharNames::SIZE); ++i){
std::cout << AllowedChars[i];
}
}
TL;DR:重新考虑枚举是否是适合这项工作的工具。枚举经常被高估到它们真正能做什么。有时,不使用枚举是更好的选择。
评论
0赞
digito_evo
1/27/2022
我的枚举类的可见性如何?我是否应该将其设为私有,因为没有其他类会访问它?
0赞
463035818_is_not_an_ai
1/27/2022
@digito_evo,如果没有人会访问它,为什么首先要使用枚举呢?对不起,我不明白这个问题(什么班级?
0赞
digito_evo
1/27/2022
我的意思是AllowedChars
0赞
463035818_is_not_an_ai
1/27/2022
@digito_evo如果你使用枚举是因为你认为它有助于迭代,那么不要使用它,它没有帮助。如果枚举是出于其他原因,那么这就是正交的。将不需要公开的东西设为私有是很好的做法,尽管我不太确定你的意思,因为他们不是某个班级的成员
0赞
digito_evo
1/27/2022
枚举类是 的成员。Foo
1赞
Eljay
1/26/2022
#2
在 C++ 中,和不提供所需的功能。enum
enum class
您可以自己实现该功能。有相当多的样板,但这可能是值得的,因为它将使调用站点更易于使用。
根据 or 的枚举定义,实现例程可以容纳有间隙的序列。enum
enum class
下面是一个示例,带有一个简单的 ,它有间隙。enum class
#include <iostream>
#include <stdexcept>
#include <utility>
using std::cout;
using std::logic_error;
using std::ostream;
using std::underlying_type_t;
namespace {
enum class Lorem {
ipsum = 10, dolor = 20, sit = 30, amet = 100, consectetur = 105, adipiscing = 111
};
auto Lorem_first() -> Lorem { return Lorem::ipsum; }
auto Lorem_last() -> Lorem { return Lorem::adipiscing; }
auto operator<<(ostream& out, Lorem e) -> ostream& {
switch(e) {
#define CASE(x) case Lorem::x: return out << #x
CASE(ipsum);
CASE(dolor);
CASE(sit);
CASE(amet);
CASE(consectetur);
CASE(adipiscing);
#undef CASE
}
throw logic_error("operator<< unknown Lorem");
}
auto operator+(Lorem e) -> underlying_type_t<decltype(e)> {
return static_cast<underlying_type_t<decltype(e)>>(e);
}
auto operator++(Lorem& e) -> Lorem& {
if (e == Lorem_last()) throw logic_error("operator++(Lorem&)");
switch(e) {
#define CASE(x, y) case Lorem::x: e = Lorem::y; break
CASE(ipsum, dolor);
CASE(dolor, sit);
CASE(sit, amet);
CASE(amet, consectetur);
CASE(consectetur, adipiscing);
#undef CASE
case Lorem::adipiscing: break;
}
return e;
}
class Lorem_Range {
bool done = false;
Lorem iter = Lorem_first();
public:
auto begin() const -> Lorem_Range const& { return *this; }
auto end() const -> Lorem_Range const& { return *this; }
auto operator*() const -> Lorem { return iter; }
bool operator!=(Lorem_Range const&) const { return !done; }
void operator++() {
if (done) {
throw logic_error("Lorem_Range::operator++");
}
if (iter == Lorem_last()) {
done = true;
} else {
++iter;
}
}
};
} // anon
int main() {
for (auto e : Lorem_Range()) {
cout << +e << ", " << e << "\n";
}
}
评论
0赞
463035818_is_not_an_ai
1/26/2022
这很好,但 OP 的情况是关于枚举器不是连续的
评论
enum class Foo { bar, quux, baz };
然后。现在,您可以使用 Foo enumdefs 的 FooX 进行迭代。vector<Foo> FooX{Foo::bar, Foo::quux, Foo::baz};