Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generate(foo) | take(n) calls foo n+1 times #819

Closed
RobertEBrown opened this issue Apr 20, 2018 · 3 comments · Fixed by #912
Closed

generate(foo) | take(n) calls foo n+1 times #819

RobertEBrown opened this issue Apr 20, 2018 · 3 comments · Fixed by #912
Labels

Comments

@RobertEBrown
Copy link

RobertEBrown commented Apr 20, 2018

I noticed that generate_n(foo, n) calls foo n times while generate(foo) | take(n) calls it n+1 times. Is this by design? If so, what is the rationale?

In some situations I would like to guarantee that foo is called exactly n times, but it seems that I can't always use generate_n. For example, say that I want to do something like this:

for_each(generate(foo), [](auto x) { return yield_if(bar(x), x); }) | take(n);

In this case, foo might be called more than n times depending on how often bar(x) returns false, but I would like to ensure that it is called exactly as many times as it takes to generate n elements and no more. I don't see how I could do it with generate_n. I guess I would need something like for_each_n, which (as far as I can see) only exists as an algorithm and not as a view.

@CaseyCarter
Copy link
Collaborator

The root cause of these generate issues is that generate_view updates its cached value on construction and iterator increment, instead of invalidating on increment and updating on dereference. We need to evaluate the perf impact of the latter semantic, and give a think to changing generate_view and/or providing a different view with that semantic.

@ericniebler
Copy link
Owner

And we should try to be consistent with other views that do similar things, like view::istream.

@morinmorin
Copy link
Contributor

I also hope that generate(f) | take(n) invokes f n times, and actually I once played with a modified version of generate/istream that implements this behavior

invalidating on increment and updating on dereference

P.S.
IIRC, the rationale for range-v3's behavior is this (p0738)

istream_iterator<int> i1(cin);
auto i2 = i1;
assert(*i1 == *i2);

We claim that this program does not assert.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants