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

In C++ I need to iterate a certain number of times, but I don't need an iteration variable. For example:

for( int x=0; x<10; ++x ) {
    /* code goes here, i do not reference "x" in this code */
}

I realize I can do this by replacing "code goes here" with a lambda or a named function, but this question is specifically about for loops.

I was hoping that C++11's range-based for loops would help:

for( auto x : boost::irange(0,10) ) {
    /* code goes here, i do not reference "x" in this code */
}

but the above gives an "unreferenced local variable" since I never explicitly reference x.

I'm wondering if there is a more elegant way to write the above for loops so that the code does not generate an "unreferenced local variable" warning.


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.


There actually is a way to make this work. All you need to do is return an std::array with the length specified by the constant you provide:

template <int N>
using range = std::array<int, N>;

int main()
{
    for (auto x : range<5>())
    {
        std::cout << "Awesome\n";
    }
}

Output:

Awesome
Awesome
Awesome
Awesome
Awesome

Here is a demo.

Note: This is assuming the range specifier is a compile-time constant, so if you have to use a variable make sure it is validly marked constexpr.


In my opinion you misuse the range-based loop. The range-based loop should be used when the logic is: "for each element in the collection do something". The whole idea is to get rid of the index variable since it isn't important. If you have a collection, you should instrument it with the necessary APIs to enable range-based iteration. If you don't have a collection, you have no business to use range-based loop (actually, that's what the compiler implies in not-so-informative way). In this situation a normal for/while loop is the natural choice.