8

I can clearly do something like this:

for(int i = 0; i < 10000; i++)
    testIteration();

But is there any std functions which does similar thing in one line? Something like that:

std::repeat(10000, testIteration);
no one special
  • 1,608
  • 13
  • 32
  • 3
    In C++11? No there's nothing. I should probably be possible to do something with [C++20 ranges](https://en.cppreference.com/w/cpp/ranges) and [`std::for_each`](https://en.cppreference.com/w/cpp/algorithm/for_each). Until C++20 is available and common, you could use [the ranges library](https://github.com/ericniebler/range-v3) which is the base for the C++20 ranges. – Some programmer dude Feb 28 '19 at 11:46
  • 7
    If you're using a loop to apply some operation to each element of a container, then there are standard algorithms. But, to essentially repeat a function call an arbitrary number of times ..... that's what loop constructs are for, and the standard library rarely tries to replicate what can more easily be done using language features. If you really want such a function, roll it yourself - just don't try to put it into namespace `std` (since doing so will give undefined behaviour). – Peter Feb 28 '19 at 11:51
  • 1
    The new std::for_each and even the new for syntax are there to help reduce boiler plate that was required frequently. Here though, it will actually result in MORE boiler plate as a rule of thumb. Consider the case where the function you wish to call is a member function of a class; one can not trivially just pass the function pointer in as you have here. – UKMonkey Feb 28 '19 at 11:58
  • 3
    This is a case where IMO you'd be highly unlikely to top that loop in readability. – StoryTeller - Unslander Monica Feb 28 '19 at 11:58
  • Well, 1/ you should really use a loop for that; 2/ there's [`std::for_each_n`](https://en.cppreference.com/w/cpp/algorithm/for_each_n) but it's not implemented in gcc nor clang; 3/ C++20 ranges could be a solution; 4/ reminder of 1/. – YSC Feb 28 '19 at 12:09
  • Can you use Boost? There's Boost counting_range and Boost irange. – Eljay Feb 28 '19 at 12:29
  • The only time I've wanted to write something like that is when I'm trying to do benchmarking. If that's what you're trying to do, maybe look at https://github.com/google/benchmark . As a framework, it makes it easier to deal with calling a function enough times to get meaningful results etc. (If that's not what you're trying to do, feel free to ignore me - but I'm predicting that you plan on putting a "start time" and "end time" around that. – Charlie Mar 01 '19 at 21:45

6 Answers6

11

In the proposed standard for C++20 there is an example for iota_view:

for (int i : iota_view{1, 10})
  cout << i << ' '; // prints: 1 2 3 4 5 6 7 8 9

But for now, range-v3 library can be used:

for (int _ : view::iota{0, 10})
    testIteration();            // calls testIteration 10 times.
Robert Andrzejuk
  • 5,076
  • 2
  • 22
  • 31
4

But is there any std functions which does similar thing in one line?

No, there is no algorithm in the standard library to do this (at least nothing that would not require to write useless boilerplate). As others already mentioned a loop is the most readable and least obfuscated way to do "something" n-times.

That being said, if you take it as an exercise to get a more terse syntax, you could write this:

#include <iostream>
struct my_counter {    
    int stop;
    struct iterator {
        int count;    
        iterator& operator++() { ++count; return *this; }
        int operator*() { return count;}
        bool operator!=(const iterator& other) { return count != other.count; }
    };
    iterator begin() { return {0}; }
    iterator end() { return {stop};}    
};

void print() { std::cout << "x"; }

int main() {
     for (auto x : my_counter{5}) print();
}

However, I would strongly advise against using something like that. Everybody knows how a loop works and what it does. Being used to for loops you can read a for loop in a blink, while anything else is uncommon, surprising and obfuscating, unless there is a standard algorithm of course (though I doubt that an algorithm for this particular case would be of great use). Why reinvent the wheel when you can use a loop?

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
4

I personally like to use a small helper function to do this.

template <typename F>
void repeat(size_t n, F f) {
  while (n--) f();
}

int main() {

   repeat(1000, [&] {
      testIteration();
   });
}

This avoids having to spell out the name of a variable. I prefer using view::iota when I need a name though.

That being said, I'm told this is confusing to read, and everyone can read a for loop, so that's probably the way to go. (Unless the function is put in std:: of course).

cigien
  • 57,834
  • 11
  • 73
  • 112
1

I know this isn't providing anything new from the above answers except that perhaps that my solution is very short. To repeat code 2 times I use a loop like the following:

for (auto _{2}; _--;) { /* this code gets repeated twice */ }

I think using the prefix operator would be less clear since to repeat code twice the loop would need to be:

for (auto _{3}; --_;) { /* this code gets repeated twice */ }

Parentheses would also of course work instead of braces, i.e.:

for (auto _(2); _--) {}
Dan H
  • 31
  • 1
  • 2
  • 7
0

Just for a reference, there is std::generate and std::generate_n which can be used, but only for array initialization by doing something like this:

int i = 0;
std::generate_n(myArray, 10000, [&]() -> int { return i++; });
no one special
  • 1,608
  • 13
  • 32
-3

What about simply defining a macro? #define FOR(N, foo, ...) for (int _i = 0; _i < N; _i++) foo(__VA_ARGS__);

For eg.

#include <iostream>

#define FOR(N, foo, ...) for (int _i = 0; _i < N; _i++) foo(__VA_ARGS__);

void bar(int a, int b)
{
    std::cout << "hello " << a+b << std::endl;
}

int main()
{
    FOR(5, bar, 12, 6);
    return 0;
}

Output:

hello 18
hello 18
hello 18
hello 18
hello 18
theWiseBro
  • 1,439
  • 12
  • 11