Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 迭代方向枚举_C++_Loops_Enums_Iterator - Fatal编程技术网

C++ 迭代方向枚举

C++ 迭代方向枚举,c++,loops,enums,iterator,C++,Loops,Enums,Iterator,我有一个方向枚举,有6个方向条目(N、NE、SE、S、SW、NW),它们基本上是图中节点的边。我经常需要迭代所有的邻居,这是通过仅使用int从0->5进行迭代来完成的 有时还需要从2->1开始迭代,当前是通过从2->2+5开始迭代并使用mod 6完成的 我能做些什么使它更安全/更易于使用而不损失性能?具有固定整数范围的for循环可以展开、内联等。基于向量的方法不能(在枚举中使用静态常量向量) 我已经在类似以下的方案中使用了枚举: struct Direction{ enum Type{

我有一个方向枚举,有6个方向条目(N、NE、SE、S、SW、NW),它们基本上是图中节点的边。我经常需要迭代所有的邻居,这是通过仅使用int从0->5进行迭代来完成的

有时还需要从2->1开始迭代,当前是通过从2->2+5开始迭代并使用mod 6完成的

我能做些什么使它更安全/更易于使用而不损失性能?具有固定整数范围的for循环可以展开、内联等。基于向量的方法不能(在枚举中使用静态常量向量)

我已经在类似以下的方案中使用了枚举:

struct Direction{
    enum Type{
        N, NE, ...
    }
    unsigned COUNT = ...;
    Type t_;
    operator Type(){return t_;}
    Direction(Type t):t_(t){assert(N<=t<COUNT);}
    explicit Direction(unsigned t):t_(t%COUNT){}
    static Direction fromUInt(unsigned t){return Direction(Type(t));}
}
结构方向{
枚举类型{
N、 嗯。。。
}
无符号计数=。。。;
t型;
运算符类型()

方向(类型t):t_uT{assert(N编辑以响应澄清

您在每次解引用时使用迭代器模
计数的想法很好。请参阅下面的反向迭代器/iterable组合。在使用
-O3
进行编译后,我检查了程序集输出。编译器展开了循环。输出为
2 1 0 5 4 3
。您可以实现正向迭代器,或者方向是一个参数。您也可以将其设置为枚举类型上的模板

不幸的是,从使用语法的角度来看,我认为这并不能像另一个答案所示那样在
do
-
循环中为您带来太多好处,至少在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;
}
(值是
int
大小的枚举,但被转换为字符串,仅输出到
std::cout

这显示了在整个集合上的迭代,具有任意的起始点。您可以使其向前或向后,并在任何枚举上对其进行模板化

我认为在你的问题中使用模是一个好主意。这段代码只是提供了一些有关枚举中常量数量的反射信息,并将它们放入数组中

这可能不适合的原因是,因为您没有使用C++11,所以数组
Direction::_values()
将在程序启动时初始化。我认为循环展开仍然可以发生,但编译器将无法对数组的内容执行任何操作。数组仍将静态分配,但元素在编译期间不可用

如果您以后可以选择使用C++11,该数组将基本上与静态初始化的
int[6]
(实际上,
Direction[6]
,其中
Direction
是一个文本
struct
类型)相同


(实际上,我想我可以公开一个
int
s数组,而不是
Direction
s数组,即使在C++98中也可以静态初始化)。

如果您想避免使用自定义库,我通常看到的方法是这样的:

#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;
}
enum Direction
{
    SE,
    S,
    SW,
    NW,
    N,
    NE,

    DIRECTION_FIRST = SE,
    DIRECTION_LAST = NE,
}
Direction current = start;
do
{
    // Do stuff with current...

    current = (current + 1) % DIRECTION_LAST;
} while(current != start);
然后,您可以使用
DIRECTION\u FIRST
DIRECTION\u LAST
在该范围内正确迭代。如果有人在不更新迭代端点的情况下向枚举中添加值,则仍有出错的空间,但将其集中在枚举中会降低这种可能性

现在,如果您假设一个任意的开始方向
start
,您可以这样迭代:

#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;
}
enum Direction
{
    SE,
    S,
    SW,
    NW,
    N,
    NE,

    DIRECTION_FIRST = SE,
    DIRECTION_LAST = NE,
}
Direction current = start;
do
{
    // Do stuff with current...

    current = (current + 1) % DIRECTION_LAST;
} while(current != start);

(如果枚举不是从0开始的,逻辑可能会更复杂一些。这可能是唯一需要首先使用
DIRECTION\u

我已经有两个构造函数使用整数参数将其转换为DIRECTION。所以我看不到任何好处。特别是我需要更多的变量(至少计数和索引)看编辑后的问题。我明白了。我想我(和其他回答者)一直在关注你问题的安全部分,从某种意义上说(我们假设)对更改枚举定义的抵制。我将编辑该问题以绘制一个迭代器。实际上,您的问题似乎已经对迭代器有了正确的想法–对每个解引用进行模运算。正如我所提到的,我认为这是正确的做法。重点是将上述代码移动到函数中或将其分解为iterators.我仍然会给出一个例子,但是是“在每个解引用上做模”足够回答吗?既然你已经有了
COUNT
并且似乎假设了一个密集的范围,那么还有什么关于安全性的问题呢?看起来很好。不可逆iterable应该足够了,但反向是一个奖励。我不允许从int构造方向以避免扩展的模,而是在迭代器中这样做。一个避免所有负数的ideo是使用start+COUNT作为开始。您可能可以执行以下操作:for(ReverseIterable::iterator iterator=Direction::Iterable(Direction::NE)。begin();iterator!=Direction::Iterable(Direction::NE)。end();++iterator)或者用一个宏来模拟C++11循环。很好的建议。我在答案中根据它们修改了代码,除了宏——我刚才提到了这一点,因为推荐它会引起争议:)此外,如果你认为反射库作为答案的一部分是个坏主意,那么,如果你编辑你的问题,说常数范围被假定为密集/连续的,我将剪掉该文本以保持答案简洁。这只适用于其他可能有类似问题的用户。问题中没有工作代码。c发布的ode仅仅是问题所指的枚举的结构。在代码下发布的只是开始的想法,而不是更多