P2881 proposes a new way to build iterators, similar to generators but with less performance overhead and better nesting (and hence composability):

struct generator123
{
    auto operator()(auto&& sink) const
    {
        std::control_flow flow;

        // With P2561: sink(1)??;
        flow = sink(1);
        if (!flow) return flow;

        // With P2561: sink(2)??;
        flow = sink(2);
        if (!flow) return flow;

        return sink(3);
    }
};

int main() {
    for (int x : generator123()) // x iterates 1, 2, 3
    {
        std::print("{}\n", x);
        if (x == 2)
            break;
    }
}

While the benefits are undisputable, it’s quite verbose without P2561 and I feel C++ is starting to have too many different iterator models.

What do you think?

One of the authors has a nice presentation about pitfalls of ye olde for loops, which was probably a big motivator too: https://www.youtube.com/watch?v=95uT0RhMGwA

  • @[email protected]
    link
    fedilink
    English
    41 year ago

    Although it looks like a nice proposal, I don’t think that it’s really workable. The major issue is that an additional scope is introduced, contrary to how for-loops normally work.

    Say you throw an exception in the loop-body, it may be a surprise if generator123 handles the exception and there is no indication in the code that your exception will go through another scope.

    And I just looked at the proposal and the 3 suggestions how to deal with exceptions and none of the proposals are good. Even worse: the operator() would act differently through compiler magic and depending on context.

    I guess the syntax has to change, it looks pretty right now, but I don’t think it can stay that way.