用迭代器行为生成函子 [英] Generating functors with iterator behavior

查看:66
本文介绍了用迭代器行为生成函子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,以前很可能曾这样问过,因为我认为我想要的是很多人想要的东西.但是我无法提出任何表达它的方式,该方式将返回我想要的搜索结果(不是google,不是这里).因此,这里的答案可能只是一个用来描述我的意思的术语.

我要实现的功能大致执行以下操作:

  1. 它可以使用函子struct/class并生成值序列 根据函子的功能来表示该函子.应该可以使用有状态函子,即应该可以实例化状态为a的函子,并使其运行直到状态为b,从而生成值{f(a),f(a + 1)的范围,...,f(b)},其中f(a + 1)代表f表示的系列中的下一项.

  2. 它的行为类似于迭代器,即可以传递而不是迭代器,例如用值填充向量.

我认为名称应该是generator或generation Iterator,因为它就是这样做的,但是我一直用这个词来寻找东西却很失败.我已经编写了自己的实现,但是它有问题,我想问一下是否有这样的事情,然后再付出更多的努力.

为了节省粘贴所有后续代码的工作,以防万一,我将其放在 ideone .我认为运行代码后,很清楚它的作用.

我当前的实现看起来像这样(这是一个简化的版本,缺少-和-之类的东西,所以是的,我确实实现了它们,因此它至少可以用作双向迭代器.我也有一个[]函数,所以我考虑将其设置为random_access.):

template <class F>
class generator{
public:
//typedefs required for iterator-use
typedef typename F::value_type value_type;
typedef typename F::step_type step_type;
typedef value_type * pointer;
typedef value_type & reference;
typedef typename F::size_type size_type;
typedef typename F::difference_type difference_type;
typedef std::bidirectional_iterator_tag iterator_category;

generator(value_type init, step_type step) : t(init), step(step){}

generator<F> &operator++() {
    t += step; return *this;
}

generator<F> &
operator+=(size_type n)
{
    t += n * step;
    return *this;
}

generator<F>
operator+(size_type n)
{
    return generator(*this) += n;
}

value_type operator*() const {
    return f(t);
}

value_type operator*() const {
    return f(t);
}

friend bool operator==(const generator<F> &lhs, const generator<F> &rhs){
    return lhs.t == rhs.t;
}
friend bool operator!=(const generator<F> &lhs, const generator<F> &rhs){
    return !(lhs == rhs);
}
private:
    value_type t;
    value_type step;
    F f;
};

我使用其他模板来尽可能轻松地提供typedef:

template <typename T>
struct simple_generator_function
{
    typedef T value_type;
    typedef T step_type;
    typedef T difference_type;
    typedef size_t size_type;
};

现在,这两个与像这样的具体生成器"一起工作:

template <typename T>
struct square_generator : public simple_generator_function<T> {

    T operator()(T t) const{
        return t * t;
    }
};

int main(void) {
    using int_sqg = generator<square_generator<int>>;
    //starting at initial value 1 take steps of size 4
    int_sqg gen(1, 1);
    //fill with all before inital + n * step
    vector<int> v(gen, gen+10);
    copy(begin(v), end(v), ostream_iterator<int>(cout, ","));
    cout << '\n';
}

长话短说:是否有一个boost或其他库,以某种可靠的方式提供了它,并且这样的iterator/functor-mix一般是什么名字?

我认为任何解决方案最多只能是InputIterator,因为据我研究,其他所有迭代器都必须从 运算符*(),在这种情况下是不可能的.很可能归结为编写一个模板,该模板将常规函子转换为InputIterator.

状态:到目前为止,答案是好的,但是在询问之前我已经花了相当长的时间思考这个问题,并且我已经考虑过类似的解决方案,所以我的问题并未得到真正的回答.我已经更新了要求1.),以-希望-更加清楚地反映我想要的内容.如果没有任何帮助,我可能会尝试将当前代码优化为更稳定的版本,并将其放在github上.

编辑2(赏金结束):

即使我对解决方案不完全满意,但将boost :: irange与boost :: transform结合起来,就像ectamur所建议的那样,它最接近于完成我想做的事情,所以我将赏赐给他.

解决方案

解决此问题的Boost.Range方法是使用transform迭代器适配器:

auto rng = boost::irange(1, 10)
    | boost::adaptors::transformed([](int i) { return i * i; });
std::vector<int> v{rng.begin(), rng.end()};

请注意,这是如何将转换的关注点与输入范围的开始/停止/步骤(可选)参数区分开的.

I have a question, which very likely has been asked like this before, because I think what I want is something that a considerable amount of people would want. However I could not come up with any way of expressing it that would return what I wanted in search (not google, not here). So maybe the answer here is just a single term used to describe what I mean.

What I want to implement is something that roughly does the following:

  1. It can take a functor struct/class and generate a sequence of values for said functor based on the functor's function. It should be possible to use a stateful functor, i.e. it should be possible to instantiate a functor in state a and let it run until it is in state b, generating the range of values {f(a), f(a+1), ..., f(b)}, where f(a+1) represents the next item in the series represented by f.

  2. It behaves like an iterator, i.e. it can be passed instead of an iterator e.g. to fill a vector with values.

I think the name should be generator or generating iterator, because that's what it does, but I have been very unsuccessful in finding something with that term. I have written my own implementation, but it has its issues, and I wanted to ask, if there is such a thing before putting any more effort into it.

To save you the work of pasting all the subsequent code in case you want to try this out I put it on ideone. I think after running the code it is pretty clear what it does.

My current implementation looks like this (fyi this is a shortened version, where some stuff like -- and - are missing, so yes I do implement them, and thus it can work at least as bidirectional iterator. I also have a [] function, so I thought about making it random_access.):

template <class F>
class generator{
public:
//typedefs required for iterator-use
typedef typename F::value_type value_type;
typedef typename F::step_type step_type;
typedef value_type * pointer;
typedef value_type & reference;
typedef typename F::size_type size_type;
typedef typename F::difference_type difference_type;
typedef std::bidirectional_iterator_tag iterator_category;

generator(value_type init, step_type step) : t(init), step(step){}

generator<F> &operator++() {
    t += step; return *this;
}

generator<F> &
operator+=(size_type n)
{
    t += n * step;
    return *this;
}

generator<F>
operator+(size_type n)
{
    return generator(*this) += n;
}

value_type operator*() const {
    return f(t);
}

value_type operator*() const {
    return f(t);
}

friend bool operator==(const generator<F> &lhs, const generator<F> &rhs){
    return lhs.t == rhs.t;
}
friend bool operator!=(const generator<F> &lhs, const generator<F> &rhs){
    return !(lhs == rhs);
}
private:
    value_type t;
    value_type step;
    F f;
};

I use a different template to provide the typedefs as easily as possible:

template <typename T>
struct simple_generator_function
{
    typedef T value_type;
    typedef T step_type;
    typedef T difference_type;
    typedef size_t size_type;
};

Right now these two work together with a concrete "generator" like this:

template <typename T>
struct square_generator : public simple_generator_function<T> {

    T operator()(T t) const{
        return t * t;
    }
};

int main(void) {
    using int_sqg = generator<square_generator<int>>;
    //starting at initial value 1 take steps of size 4
    int_sqg gen(1, 1);
    //fill with all before inital + n * step
    vector<int> v(gen, gen+10);
    copy(begin(v), end(v), ostream_iterator<int>(cout, ","));
    cout << '\n';
}

Long story short: Is there a boost or other library, which offers this in a somewhat reliable manner and what is the name of such a iterator/functor-mix in general?

EDIT 1:

I think any solution can at best be an InputIterator, because as far as I have researched it, all other iterators would have to return a reference from operator*(), which is out of the question in this case. Very likely, it comes down to writing a template that converts a regular functor into an InputIterator.

Status: the answers so far are good, but I have put some thought into this for quite a while before asking, and I had thought about similar solutions, so my question is not really answered. I have updated requirement 1.) to - hopefully - reflect more clearly what I want. If nothing comes of this I will probably try to refine my current code into a more stable version and put it on github.

EDIT 2 (End of Bounty):

Even though I am not entirely satisfied with the solution, boost::irange in combination with boost::transformed as ectamur suggested come closest to doing what I want, so I will give the bounty to him.

解决方案

The Boost.Range way to solve this problem is to use the transform iterator adaptor:

auto rng = boost::irange(1, 10)
    | boost::adaptors::transformed([](int i) { return i * i; });
std::vector<int> v{rng.begin(), rng.end()};

Note how this separates the concerns of the transformation from the start/stop/step (optional) parameters of the input range.

这篇关于用迭代器行为生成函子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆