针对澄清的修改
您关于在每次解除引用时将迭代器取模COUNT
的想法是一个好主意。请参见下面的反向迭代器/可迭代组合。我使用-O3
编译器编译后检查了汇编输出。编译器展开了循环。输出为2 1 0 5 4 3
。您可以实现一个正向迭代器,或将方向作为参数。您还可以将其制作成枚举类型的模板。
不幸的是,在使用语法方面,我认为这与另一个答案中显示的do
-while
循环相比,并没有带来太多好处-至少在C++11之前是如此。它确实隐藏了各种索引变量,并帮助您避免出错,但更加冗长。
#include <iostream>
struct Direction {
enum Type {N, NE, SE, S, SW, NW};
static const unsigned COUNT = 6;
Type t_;
operator Type() { return t_; }
Direction(Type t) : t_(t) { }
explicit Direction(unsigned t) : t_(Type(t % COUNT)) { }
};
struct ReverseIterable {
const unsigned start_;
struct iterator {
unsigned offset_;
explicit iterator(unsigned offset) : offset_(offset) { }
Direction operator *() { return Direction(offset_); }
iterator& operator++() { --offset_; return *this; }
bool operator ==(const iterator &other)
{ return offset_ == other.offset_; }
bool operator !=(const iterator &other) { return !(*this == other); }
};
explicit ReverseIterable(Direction start) : start_(start) { }
iterator begin() { return iterator(start_ + Direction::COUNT); }
iterator end() { return iterator(start_); }
};
int main()
{
ReverseIterable range = ReverseIterable(Direction::SE);
for (ReverseIterable::iterator iterator = range.begin();
iterator != range.end(); ++iterator) {
std::cout << (int)*iterator << " ";
}
std::cout << std::endl;
return 0;
}
在C++11中,循环可以是这样的:
for (Direction direction : ReverseIterable(Direction::SE))
std::cout << (int)direction << " ";
std::cout << std::endl;
“您可以使用宏在C++98中实现类似的功能。” “我暂时保留了原始答案,因为如果枚举定义发生更改,则可以更轻松地进行维护,而且它允许稀疏范围。非常相似的迭代器可以在其基础上实现。”
原始答案专注于安全
这可能对您的目的来说有些过度,也可能由于我将在下面进一步描述的原因而不合适。然而,您可以使用这个库(免责声明:我是作者):https://github.com/aantron/better-enums编写如下代码:
#include <iostream>
#include <enum.h>
ENUM(Direction, int, N, NE, SE, S, SW, NW)
int main()
{
size_t iterations = Direction::_size();
size_t index = 2;
for (size_t count = 0; count < iterations; ++count) {
std::cout << Direction::_values()[index] << " ";
index = (index + 1) % Direction::_size();
}
std::cout << std::endl;
return 0;
}
输出:
SE S SW NW N NE
这段代码中,枚举值是 int 类型的,但只有在输出到 std::cout 时才转换为字符串。
这展示了对整个集合的迭代,起始点是任意的。您可以使其向前或向后移动,并将其模板化为任何枚举类型。
我认为使用取模运算符就像您的问题一样是一个好主意。这段代码仅提供有关枚举常量数量的反射信息,并将它们放入数组中。
可能不适合的原因是,由于您没有使用 C++11,数组 Direction::_values() 将在程序启动时初始化。我认为循环展开仍然可以发生,但编译器无法处理数组的内容。数组仍将被静态分配,但元素在编译期间不可用。
如果您以后有使用 C++11 的选项,则该数组基本上与静态初始化的 int[6](实际上是 Direction[6],其中 Direction 是一个字面量的 struct 类型)相同。
实际上,我想我可以暴露一个
int
数组而不是
Direction
,这将在C++98中静态初始化。