如何解决有没有办法在不知道 C++ 大小的情况下迭代枚举
你好,我有以下枚举
enum params_Solver {
params_Solver_Lorem,params_Solver_Ipsum,params_Solver_Simply,params_Solver_Dummy,params_Solver_Test,params_Solver_typesetting,params_Solver_Industry,params_Solver_Scrambled
};
for (auto enum_member: params_Solver)
{
print(index,enum_member); // output looks like this: "0,params_Solver_Lorem","1,params_Solver_Ipsum" etc
}
有没有办法做到这一点?
编辑:我无法控制枚举。此枚举由来自第 3 部分库的不同文件提供。我可能可以复制它但不能更改原始枚举。我想将枚举库的成员写入不同的文件。
解决方法
没有。至少不是直接的。枚举实际上不是一组常量。相反,它们是一种带有一组命名常量的类型。区别在于:例如 42
是一个完全有效的 params_Solver
值,它只是没有名称。
启用迭代的常用方法是添加标记值:
enum params_Solver {
params_Solver_Lorem,params_Solver_Ipsum,params_Solver_Simply,params_Solver_Dummy,params_Solver_Test,params_Solver_Typesetting,params_Solver_Industry,params_Solver_Scrambled,num_params_Solver // <----
};
然后从 0
迭代到 num_params_Solver
。好消息是您可以添加另一个常量,而 num_params_Solver
仍然是正确的。限制是它只适用于没有自定义值的枚举。
常用方法
您可以通过这种方式在枚举末尾添加一个项目:
enum params_Solver {
params_Solver_Lorem,Last
};
然后循环:
for (int i = params_Solver_Lorem; i != Last; i++) {
// some code
}
如果您将值分配给默认值以外的枚举成员,则此解决方案不起作用。
其他方式
您可以使用常规数组而无需添加最后一个元素。然而,语法是非常多余的,因为您必须自己指定枚举的成员:
constexpr params_Solver members[] {
params_Solver_Lorem,params_Solver_Scrambled
};
然后您可以使用以下方法遍历枚举:
for (auto m: members) {
// Some code
}
,
在枚举的基础类型中可表示的所有值都是枚举的有效值,无论是否给定名称,并且在 64 位枚举范围内迭代可能需要比您愿意等待的时间更长的时间。 .:)
另一个复杂的问题是,如果您只想迭代命名的枚举器,那是可能的,但需要更多的工作和一些考虑。如前所述,如果您没有为您的枚举器提供任何自定义值,那么它们将从零开始并递增。但是,您可以在数字中设置间隙,可以向后跳,可以重复。两个具有相同值的枚举器算作一次迭代还是每个名称一个?不同的情况会有不同的答案。
如果您在没有自定义枚举值的情况下执行此操作,您可以在列表末尾添加一个额外的“虚拟”值,并将其视为枚举器的计数。但是,如果您有间隙、重复或从 0 以外的值开始,这将是错误的。如果有人在虚拟值之后添加新的枚举值,它也会失败。
有一些 3rd 方库可以帮助解决这个问题。如果您不介意一些额外的代码,“Better Enums”开源库是非常有用的仅头文件库。 https://github.com/aantron/better-enums 它通过漂亮的语法为您的枚举提供元数据,允许迭代器、范围循环使用、转换为/从字符串名称等等。
,C++ 没有为您正在尝试做的事情提供内在支持。
您可以添加一些样板来完成您想要的操作,以便使用枚举范围的代码不知道枚举。在代码示例中,该知识封装在 params_Solver_Range
帮助器类中。
#include <iostream>
#include <stdexcept>
#include <utility>
using std::ostream;
using std::cout;
using std::underlying_type_t;
using std::logic_error;
namespace {
enum class params_Solver {
Lorem,Ipsum,Simply,Dummy,Test,Typesetting,Industry,Scrambled
};
auto operator<<(ostream& out,params_Solver e) -> ostream& {
#define CASE(x) case params_Solver::x: return out << #x
switch(e) {
CASE(Lorem);
CASE(Ipsum);
CASE(Simply);
CASE(Dummy);
CASE(Test);
CASE(Typesetting);
CASE(Industry);
CASE(Scrambled);
}
#undef CASE
throw logic_error("unknown params_Solver");
}
auto operator+(params_Solver e) {
return static_cast<underlying_type_t<decltype(e)>>(e);
}
auto operator++(params_Solver& e) -> params_Solver& {
if (e == params_Solver::Scrambled) throw logic_error("increment params_Solver");
e = static_cast<params_Solver>(+e + 1);
return e;
}
class params_Solver_Range {
bool done = false;
params_Solver iter = params_Solver::Lorem;
public:
auto begin() const -> params_Solver_Range const& { return *this; }
auto end() const -> params_Solver_Range const& { return *this; }
auto operator*() const -> params_Solver { return iter; }
bool operator!=(params_Solver_Range const&) const { return !done; }
void operator++() {
if (done) throw logic_error("increment past end");
if (iter == params_Solver::Scrambled) done = true;
else ++iter;
}
};
} // anon
int main() {
for (auto e : params_Solver_Range()) {
cout << +e << "," << e << "\n";
}
}
,
没有。做你想做的反射提案可能会在 [c++23] 中到达。
如果没有它,您可以将 enum
复制粘贴(可能引用它)到一个数组中,然后遍历该副本。
constexpr char const* members[] {
"params_Solver_Lorem","params_Solver_Ipsum",//etc
};
然后在上面做一个 for 循环。
for (char const* const& enum_member: members)
{
auto index = static_cast<long long unsigned>(&enum_member-members);
printf("%llu,%s\n",index,enum_member);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。