STL 或 boost 中的 C++ range/xrange 等价物?

2021-12-24 00:00:00 iterator c++ boost

在 STL 或 boost 中是否有 C++ 等效的 python Xrange 生成器?

Is there C++ equivalent for python Xrange generator in either STL or boost?

xrange 基本上会在每次调用 ++ 运算符时生成递增的数字.构造函数是这样的:

xrange basically generates incremented number with each call to ++ operator. the constructor is like this:

xrange(first, last, increment)

希望使用 boost 来做这样的事情:

was hoping to do something like this using boost for each:

foreach(int i, xrange(N))

我.我知道 for 循环.在我看来,它们太多样板了.

I. am aware of the for loop. in my opinion they are too much boilerplate.

谢谢

我想要这样做的主要原因是因为我使用语音到文本软件,即使使用代码完成,编程循环通常的方式也很困难.拥有可发音的结构会更有效率.

my main reason for wanting to do so is because i use speech to text software, and programming loop usual way is difficult, even if using code completion. It is much more efficient to have pronounceable constructs.

许多循环从零开始并以一递增,这是范围的默认值.我发现python构造更直观

many loops start with zero and increment by one, which is default for range. I find python construct more intuitive

 for(int i = 0; i < N; ++i)
 foreach(int i, range(N))

需要以范围为参数的函数:

functions which need to take range as argument:

 Function(int start, int and, int inc);
 function(xrange r);

我了解语言之间的差异,但是如果 Python 中的特定构造对我非常有用并且可以在 C++ 中有效实现,我认为没有理由不使用它.因为每个构造对于 C++ 来说都是陌生的,无论人们如何使用它.

I understand differences between languages, however if a particular construct in python is very useful for me and can be implemented efficiently in C++, I do not see a reason not to use it. For each construct is foreign to C++ as well however people use it.

我把我的实现和示例用法放在了页面底部.

I put my implementation at the bottom of the page as well the example usage.

在我的领域中,我使用多维数组,通常使用 4 张量.所以我经常会得到 4 个具有不同范围/增量的嵌套循环来计算规范化、索引等.这些不一定是性能循环,我更关心正确性的可读性和修改能力.

in my domain i work with multidimensional arrays, often rank 4 tensor. so I would often end up with 4 nested loops with different ranges/increments to compute normalization, indexes, etc. those are not necessarily performance loops, and I am more concerned with correctness readability and ability to modify.

例如

int function(int ifirst, int ilast, int jfirst, int jlast, ...);
versus
int function(range irange, range jrange, ...);

在上面,如果需要不同的跨步,你必须传递更多的变量,修改循环等.最终你会得到大量整数/几乎相同的循环.

In the above, if different strids are needed, you have to pass more variables, modify loops, etc. eventually you end up with a mass of integers/nearly identical loops.

foreach 和 range 正好解决了我的问题.对普通 C++ 程序员的熟悉程度在我的关注列表中并不高 - 问题域相当模糊,有很多元编程、SSE 内在生成代码.

foreach and range solve my problem exactly. familiarity to average C++ programmer is not high on my list of concerns - problem domain is a rather obscure, there is a lot of meta-programming, SSE intrinsic, generated code.

推荐答案

Boost 有 counting_iterator 据我所知,这似乎只允许以 1 为步长递增.对于完整的 xrange 功能,您可能需要自己实现类似的迭代器.

Boost has counting_iterator as far as I know, which seems to allow only incrementing in steps of 1. For full xrange functionality you might need to implement a similar iterator yourself.

总而言之,它看起来像这样(为 xrange 的第三次重载添加了一个迭代器,以使用 boost 的迭代器外观):

All in all it could look like this (edit: added an iterator for the third overload of xrange, to play around with boost's iterator facade):

#include <iostream>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/foreach.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <cassert>

template <class T>
boost::iterator_range<boost::counting_iterator<T> > xrange(T to)
{
    //these assertions are somewhat problematic:
    //might produce warnings, if T is unsigned
    assert(T() <= to);
    return boost::make_iterator_range(boost::counting_iterator<T>(0), boost::counting_iterator<T>(to));
}

template <class T>
boost::iterator_range<boost::counting_iterator<T> > xrange(T from, T to)
{
    assert(from <= to);
    return boost::make_iterator_range(boost::counting_iterator<T>(from), boost::counting_iterator<T>(to));
}

//iterator that can do increments in steps (positive and negative)
template <class T>
class xrange_iterator:
    public boost::iterator_facade<xrange_iterator<T>, const T, std::forward_iterator_tag>
{
    T value, incr;
public:
    xrange_iterator(T value, T incr = T()): value(value), incr(incr) {}
private:
    friend class boost::iterator_core_access;
    void increment() { value += incr; }
    bool equal(const xrange_iterator& other) const
    {
        //this is probably somewhat problematic, assuming that the "end iterator"
        //is always the right-hand value?
        return (incr >= 0 && value >= other.value) || (incr < 0 && value <= other.value);
    }
    const T& dereference() const { return value; }
};

template <class T>
boost::iterator_range<xrange_iterator<T> > xrange(T from, T to, T increment)
{
    assert((increment >= T() && from <= to) || (increment < T() && from >= to));
    return boost::make_iterator_range(xrange_iterator<T>(from, increment), xrange_iterator<T>(to));
}

int main()
{
    BOOST_FOREACH(int i, xrange(10)) {
        std::cout << i << ' ';
    }
    BOOST_FOREACH(int i, xrange(10, 20)) {
        std::cout << i << ' ';
    }
    std::cout << '
';
    BOOST_FOREACH(int i, xrange(0, 46, 5)) {
        std::cout << i << ' ';
    }
    BOOST_FOREACH(int i, xrange(10, 0, -1)) {
        std::cout << i << ' ';
    }
}

正如其他人所说,我不认为这比正常的 for 循环更能让您受益.

As others are saying, I don't see this buying you much over a normal for loop.

相关文章