C++11 range-based for loops without loop variable

Edit now with 100% fewer loop variables declared.

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

Use it as:

repeat(10, f);

or

repeat(10, [] { f(); });

or

int g(int);
repeat(10, std::bind(g, 42));

See it live at http://ideone.com/4k83TJ


There may be a way to do it but I very much doubt it would be more elegant. What you have in that first loop is already the correct way to do it, limiting the scope/lifetime of the loop variable.

I would simply ignore the unused variable warning (it's only an indication from the compiler that something may be wrong, after all) or use the compiler facilities (if available) to simply turn off the warning at that point.

This may be possible with some sort of #pragma depending on your environment, or some implementations allow you to do things like:

for (int x = 0; x < 10; ++x) {
    (void)x;

    // Other code goes here, that does not reference "x".
}

I've seen that void trick used for unused parameters in function bodies.


Assuming 10 is a compile time constant...

#include <cstddef>
#include <utility>
template<std::size_t N>
struct do_N_times_type {
  template<typename Lambda>
  void operator()( Lambda&& closure ) const {
    closure();
    do_N_times_type<N-1>()(std::forward<Lambda>(closure));
  }
};
template<>
struct do_N_times_type<1> {
  template<typename Lambda>
  void operator()( Lambda&& closure ) const {
    std::forward<Lambda>(closure)();
  }
};
template<>
struct do_N_times_type<0> {
  template<typename Lambda>
  void operator()( Lambda&& closure ) const {
  }
};

template<std::size_t N, typename Lambda>
void do_N_times( Lambda&& closure ) {
  do_N_times_type<N>()( std::forward<Lambda>(closure) );
};
#include <iostream>
void f() {
  std::cout << "did it!\n";
}
int main() {
  do_N_times<10>([&]{
    f();
  });
}

or just

int main() {
  do_N_times<10>(f);
}

Other ridiculous methods:

Write a range iterator (I call mine index) that produces an range of iterator-on-integral types (I default to std::size_t). Then type:

for( auto _:index_range(10) )

which uses a variable (_) but looks exceedingly confusing.

Another crazy approach would be to create a python-like generator. Writing a generator wrapper that takes an iterable range and produces a function that returns std::optional on the value_type of the range isn't tricky.

We can then do:

auto _ = make_generator( index_range(10) );
while(_()) {
}

which creates a temporary variable as well, and is even more obtuse.

We could write a looping function that operates on generators:

template<typename Generator, typename Lambda>
void While( Generator&& g, Lambda&& l ) {
  while(true) {
    auto opt = g();
    if (!opt) return;
    l(*opt);
  }
}

which we then call like:

While( make_generator( index_range(10) ), [&](auto&&){
  f();
});

but this both creates some temporary variables in the function, and is more ridiculous than the last, and relies on features of C++1y which has not even been finalized.

Those where my attempts to create a variable-less way to repeat something 10 times.

But really, I'd just do the loop.

You can almost certainly block the warning by typing x=x;

Or write a function

template<typename Unused>
void unused( Unused&& ) {}

and call unused(x); -- the variable x is used, and its name is dropped inside, so the compiler may not warn you about it inside.

So try this:

template<typename Unused>
void unused( Unused&& ) {}
for(int x{};x<10;++x) {
  unused(x);
  f();
}

which should suppress the warning, and be actually easy to understand.

Tags:

C++

C++11