Reputation: 881
Very simply, is there a simpler way to repeat a block for a certain number of times, where the block inside does not need the counter variable? The trivial solution is of course
for (int i = 0; i < repetitions; ++i) {
//do your thing, i is not used here
}
However, now that we have ranged for, standard algorithms and other fancy constructs for iterating over containers, in comparison this is actually starting to feel like a lot of boilerplate and details for what should be an even simpler case. For example we're not interested in the variable i
at all etc.
The closest thing to a concrete problem is this: when I encounter a for loop such as above, I need to scan through the code block to see if i
is actually used, or if it's just a dummy counter. The declaration of a for loop which actually wants to do something with the integers 0 to repetitions - 1
will look identical. So a repeat (n)
-type construct would have the extra semantic information that all the iterations will be the same, except for potential side-effects.
One option is to make a template
template<class functor>
repeat(functor fun, unsigned n) {
for (unsigned i = 0; i < n; ++i)
fun();
}
and call
repeat([&](){
//do your thing
}, repetitions)
but this really seems like overengineered overkill for a simple problem. This could be macroized to make the usage a bit nicer, but that certainly won't help with the overengineered feel.
So one valid answer is that I'm on a wild goose chase here, and should just use the good old for loop with counter.
Any standard C++ is fine, including upcoming standards.
Related questions such as How to create a loop in C++ that loops a certain amount of times? and How to create a loop in C++ that loops a certain amount of times? are beginners asking for some way to achieve this, whereas I'm specifically asking for a modern, clean and elegant way to achieve this. c++ repeat N iterations is very close, though the difference here is that I'm asking for any alternatives, not necessarily included in std::
.
Upvotes: 14
Views: 17524
Reputation: 1028
"Hand-made" repeat
is somewhat problematic. Should there be break
or continue
? One can throw an exception from "inside" repat, and "break out". But some projects do disallow exceptions.
Also in the presence of a standard for range loop
one does not need to "scan through the code block to see if i is actually used, or if it's just a dummy counter.". That argument is done with.
To have compiler intrinsic repeat
might be not such a bad idea, and certainly would be easy to add.
// C++ 25 -- perhaps
repeat( 42 ) {
std::printf("\nThis is 42 lines of text.");
continue; // allowed
break ; // allowed
}
REPEAT(N) macro is tempting, but macros are forbiden. If not compiler intrinsic, user defined repeat
is not that "simple and elegant". Here is what I might be using:
// the repeat
template< typename CALLABLE_, typename ... Args >
void repeat( size_t N, CALLABLE_ fun_, Args ... args)
{
for ( auto k = 0 ; k < N ; k++ ) {
fun_(args ...);
}
}
Now to use the above one would most likely call it with lambda. Usage is as expected:
// reachable from inside `repeat`
int result {} ;
repeat( 0xF ,
[&] {
::std::wprintf( L"\n random word:\t '%s'", random_word());
result++ ;
}
);
The "modern way" is not always "the elegant vintage way".
Upvotes: 0
Reputation:
Modern does not necessarily means using newest feautures.
One of the easiest solutions it to use simple for
loop as below:
for (auto _ = times; _--;) [[likely]] statement;
…where:
times
is a constant integer literal with no suffix (ie 3).statement
is a statement to be executed times
times.Example usage:
constexpr auto f(int Value) noexcept
{
for (auto _ = 3; _--;) [[likely]] ++Value;
return Value;
}
int main()
{
constexpr auto i = f(2);
return i;
}
Constant i
variable is declared with initial value of 2
, increased 3 times by one in f
's for
loop, taking final value of 5
and being used as program returned value.
[[likely]]
attribute in future.times
constant is likely to be zero, use [[unlikely]]
attribute instead._
name is commonly used as meaningless to name a discardable variable.Upvotes: 6
Reputation: 6154
Instead of a modern C++ way, how about an old C way but without an index:
while (repetitions--)
fun();
Of course you still need a variable for repetitions
though.
Upvotes: 6