在枚举上索引循环是多么可怕 - 或者它是否完全可以接受?
我定义了一个枚举。文字的值是默认值。指定的值没有任何意义,没有任何意义,将来添加的任何文字的值也没有任何意义。它被定义为限制允许的值并使事情更容易遵循。因此,值始终从0开始并增加1.
我可以像这样设置一个循环:
enum MyEnum
{
value1,
value2,
value3,
maxValue
}
for(MyEnum i = value1; i < maxValue; i = static_cast<MyEnum>(i+1)){}
答案 0 :(得分:9)
我刚才为这些案例编写了一个枚举迭代器
enum Foo {
A, B, C, Last
};
typedef litb::enum_iterator<Foo, A, Last> FooIterator;
int main() {
FooIterator b(A), e;
std::cout << std::distance(b, e) << " values:" << std::endl;
std::copy(b, e, std::ostream_iterator<Foo>(std::cout, "\n"));
while(b != e) doIt(*b++);
}
如果您有兴趣,这是代码。如果您愿意,可以通过提供+
,<
,[]
和朋友将其扩展为随机访问迭代器。像std::distance
这样的算法会感谢你为随后的随机访问迭代器提供O(1)
时间复杂度。
#include <cassert>
namespace litb {
template<typename Enum, Enum Begin, Enum End>
struct enum_iterator
: std::iterator<std::bidirectional_iterator_tag, Enum> {
enum_iterator():c(End) { }
enum_iterator(Enum c):c(c) { }
enum_iterator &operator=(Enum c) {
this->assign(c);
return *this;
}
enum_iterator &operator++() {
this->inc();
return *this;
}
enum_iterator operator++(int) {
enum_iterator cpy(*this);
this->inc();
return cpy;
}
enum_iterator &operator--() {
this->dec();
return *this;
}
enum_iterator operator--(int) {
enum_iterator cpy(*this);
this->dec();
return cpy;
}
Enum operator*() const {
assert(c != End && "not dereferencable!");
return c;
}
bool equals(enum_iterator other) const {
return other.c == c;
}
private:
void assign(Enum c) {
assert(c >= Begin && c <= End);
this->c = c;
}
void inc() {
assert(c != End && "incrementing past end");
c = static_cast<Enum>(c + 1);
}
void dec() {
assert(c != Begin && "decrementing beyond begin");
c = static_cast<Enum>(c - 1);
}
private:
Enum c;
};
template<typename Enum, Enum Begin, Enum End>
bool operator==(enum_iterator<Enum, Begin, End> e1, enum_iterator<Enum, Begin, End> e2) {
return e1.equals(e2);
}
template<typename Enum, Enum Begin, Enum End>
bool operator!=(enum_iterator<Enum, Begin, End> e1, enum_iterator<Enum, Begin, End> e2) {
return !(e1 == e2);
}
} // litb
答案 1 :(得分:4)
就我而言,这很好。我肯定有些纯粹的东西会在某处发生,但就语言规范而言,该代码将正常工作,所以如果它让你的生活更轻松,你应该随意去做。
答案 2 :(得分:2)
这样做可能会有所帮助。
enum MyEnum
{
first,
value1,
value2,
value3,
last
}
答案 3 :(得分:0)
只要您没有专门设置枚举值的值,那就没问题。你的例子很好,但这可能很糟糕:
// this would be bad
enum MyEnum
{
value1,
value2 = 2,
value3,
maxValue
};
正如7.2 / 1中的标准所述:
枚举器定义 没有初始值设定项为枚举数提供通过增加前一个值获得的值 一位普查员。
答案 4 :(得分:0)
我不知道具体使用什么实际上有用,我认为是错误的代码。 如果在许多图书馆中看到这样的东西怎么办?
enum MyEnum
{
value1,
value2,
value3,
maxValue = 99999;
};
答案 5 :(得分:0)
因此值始终开始 在0并且增加1。
请记住,除非将其写入您工作的编码标准,否则维护程序员会在6个月内出现并更改枚举,如:
enum MyEnum
{
value1,
value2 = 5,
value3,
maxValue
}
由于新的要求,您将解释为什么他们的合法更改破坏了申请。
要将值附加到名称,您可以使用地图:
typedef std::map<std::string,int> ValueMap;
ValueMap myMap;
myMap.insert(make_pair("value1", 0));
myMap.insert(make_pair("value2", 1));
myMap.insert(make_pair("value3", 2));
for( ValueMap::iterator iter = theMap.begin(); iter != theMap.end(); ++iter )
{
func(iter->second);
}
如果名称无关紧要,可以使用C风格的数组:
int values[] = { 0, 1, 2 };
int valuesSize = sizeof(values) / sizeof(values[0]);
for (int i = 0; i < valuesSize; ++i)
{
func(values[i]);
}
使用std :: vector的类似方法。
另外,如果你说的是真的,the values will always start at 0 and increase by 1
那么我很困惑为什么这不起作用:
const int categoryStartValue = 0;
const int categoryEndValue = 4;
for (int i = categoryStartValue; i < categoryEndValue; ++i)
{
func(i);
}
答案 6 :(得分:0)
这不容易......
我找到的唯一解决方案是实际在枚举上实现一个类,然后使用宏来定义枚举...
DEFINE_NEW_ENUM(MyEnum, (value1)(value2)(value3))
基本思想是将值存储在STL容器中,根据MyEnum
符号静态存储在模板类中。通过这种方式,您可以获得完美定义的迭代,甚至可以获得无效状态(因为end()
)。
我使用了vector
的{{1}},这样我就可以从日志中的漂亮打印和长时间的序列化中受益(并且因为它比一组关联容器更快,只需很少的数据集并且需要更少的数据存储器)。
我还没有找到更好的方法,C ++ 11最终是否会在枚举上进行迭代?
答案 7 :(得分:0)
我通常在需要迭代时在我的枚举中定义开始值和结束值,使用如下特殊语法(使用doxygen样式注释来澄清):
enum FooType {
FT__BEGIN = 0, ///< iteration sentinel
FT_BAR = FT__BEGIN, ///< yarr!
FT_BAZ, ///< later, when the buzz hits
FT_BEEP, ///< makes things go beep
FT_BOOP, ///< makes things go boop
FT__END ///< iteration sentinel
}
FT_可以帮助命名空间(以避免枚举之间的冲突)和双下划线有助于区分实际值和迭代标记。
旁注:
写这篇文章我开始担心用户标识符不允许双下划线(它的实现保留,IIRC?),但我还没遇到问题(用这种方式编写代码5到6年后)。它可能没问题,因为我总是将所有类型都放在命名空间中,以避免污染和干扰全局命名空间。
答案 8 :(得分:-1)
您可以使用switch语句包装循环体以防止非增量值。它可能超级慢,如maxValue = 9999;情况,但它可能不是有史以来最糟糕的事情。我在代码库中一直看到这种风格
enum MyEnum {
value1,
value2,
value3,
maxValue
}
for(MyEnum i = value1; i < maxValue; i = static_cast<MyEnum>(i+1)){
switch(i)
{
case value1:
case value2:
case value3:
//actual code
}
}