NoSenseEtAl
NoSenseEtAl

Reputation: 30028

Repeat n times with C++ ranges without dummy variable

I am trying to implement repeat n times using C++20 ranges. It works, but all approaches I can think of need a dummy variable (one for the for loop variable, other for arity of lambda).

static constexpr int kIterations = 3;

void f1(){
    auto c = '.';
    for (const auto _ :std::views::iota(0)| std::views::take(kIterations) ) {
        std::cout << c;
    }
    std::cout << std::endl;
}

void f2(){
    auto c = '.';
    std::ranges::for_each(std::views::iota(0)| std::views::take(kIterations), [&c](const auto _) {
        std::cout << c;
    });
    std::cout << std::endl;
}

Is there a way to do this with C++20 ranges without the need for dummy variable (_ in my case, but even unnamed requires const? auto).

notes:

Upvotes: 2

Views: 1304

Answers (2)

Enlico
Enlico

Reputation: 28406

If you could use both C++20 <ranges> and repeat_n from Range-v3, then this could be an approach?

#include <algorithm>
#include <functional>
#include <iostream>
#include <boost/hof/lift.hpp>
#include <range/v3/view/repeat_n.hpp>
#include <ranges>

using ranges::views::repeat_n;
using namespace std::ranges::views;
using namespace std::ranges;

auto constexpr invoke = BOOST_HOF_LIFT(std::invoke); // what a pity we need this

static constexpr int kIterations = 3;

void f() {
    char c = '.';
    for_each(repeat_n([c]{ std::cout << c << std::endl; },
                      kIterations),
             invoke);
}

int main()
{
    f();
}

The lambda [c]{ std::cout << c << std::endl; } is nullary as it isn't passed any value, and there's no for loop with a dummy variable.

Upvotes: 2

Nicol Bolas
Nicol Bolas

Reputation: 473407

A range is a means of iterating over a set of values. You can manufacture those values on demand rather than accessing them from storage, as iota does. But ranges are about iterating over a sequence of values.

So any range-based iteration mechanism is going to involve an object representing, at least, the current position in the range. That's just the nature of the beast.

Yes, you could write your own version of ranges::for_each which "iterates" over a range but doesn't actually pass those values to the functor:

template<std::ranges::input_range Rng, std::invocable Func>
decltype(auto) iterate_no_element(Rng &&rng, Func func)
{
  return std::ranges::for_each(std::forward<Rng>(rng), [func](auto const&){func();})
}

But the standard has no such function.

Upvotes: 4

Related Questions