C ++ 11 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 understand that I can do this by replacing the "code here" with a lambda or a named function, but this question is specifically devoted to loops.

I was hoping C ++ 11, based on ranges 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 "unaccepted local variable" as I never refer to x.

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

+55
c ++ c ++ 11
Jul 17 '13 at 22:52
source share
10 answers

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

I would simply ignore the warning of an unused variable (this is just an indication from the compiler that something might be wrong in the end) or use the compiler tools (if available) to simply turn off the warning at this point.

This may be possible with some kind 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 saw that the void trick is used for unused parameters in function bodies.

+18
Jul 17 '13 at 23:02
source share

Edit now with 100% smaller declared loop variables.

 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)); 

Watch live http://ideone.com/4k83TJ

+45
Jul 17 '13 at 23:09
source share

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 simply

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

Other funny methods:

Write a range iterator (I call my index ) that creates a range of types of iterators on the integral (by default I am std::size_t ). Then enter:

 for( auto _:index_range(10) ) 

which uses the variable ( _ ) but looks extremely confusing.

Another crazy approach would be to create a generator like python. Writing a generator shell that takes an iterable range and creates a function that returns std::optional in the value_type range is not complicated.

Then we can:

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

which also creates a temporary variable and even dumber ones.

We could write a loop function that works with 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:

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

but this creates both temporary variables in the function and is more funny than the last ones, and relies on C ++ 1y functions that have not yet been finalized.

Those where my attempts to create a method without a variable to repeat something 10 times.

But actually, I would just do a loop.

You will 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 entered inside, so the compiler may not warn you about this inside.

So try the following:

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

which should suppress the warning, and really easy to understand.

+9
Jul 17 '13 at 23:10
source share

There is actually a way to do this work. All you have to do is return 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:

Tall
Tall
Tall
Tall
Tall

Below is a demo .

Note. The range specifier is assumed to be a compile-time constant, so if you need to use a variable, make sure that it is really marked with constexpr .

+8
Jul 18 '13 at 0:05
source share

There is no way to make a performance-based range for simply repeating multiple numbers.

Circuits based on C ++ 11 ranges require expression in a range, which can be:

  • array or
  • class having
    • Member functions begin() and end() or
    • available free functions begin() and end() (via ADL)

In addition to this: a range based on some costs:

 for ( for_range_declaration : expression ) statement 

expands to

 range_init = (expression) { auto && __range = range_init; for ( auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin ) { for_range_declaration = *__begin; statement; } } 

Where begin_expr and end_expr are obtained through checking the array or begin() / end() pairs.

I don’t think it gets any cleaner than a simple for-loop. Especially regarding performance. No calls, just a simple loop.

The only way I can understand to make it more elegant (where elegant, in my opinion, depends on my opinion), you can use the size or unsigned type here:

 for(size_t x(0U); x<10U; ++x) f(); 
+4
Jul 17 '13 at 23:14
source share

In my opinion, you are abusing a range based loop. A range-based loop should be used when the logic: "do something for each item in the collection." The whole idea is to get rid of the index variable, since it is not important. If you have a collection, you should use it with the necessary APIs to enable range-based iteration. If you don’t have a collection, you don’t need to use a range-based loop (in fact, this is what the compiler means in a less informative way). In this situation, normal for the / while loop is a natural choice.

+4
Jul 18 '13 at 18:09
source share

What is the best answer in https://stackoverflow.com/a/22094/ ... : how to determine the UNUSED macro that will be used throughout your code base, which suppresses this warning. Portable way.

+4
Feb 19 '14 at 11:24
source share

You can use STL along with lambda expression.

 #include <algorithm> #include <iostream> int main() { int a[] = {1,2,3,4,5,6}; std::for_each(std::begin(a), std::end(a), [](int){std::cout << "Don't care" << std::endl;}); } 

This approach also works for any containers, such as vectors or lists. Let vector<int> a , then you will call a.begin() and a.end() . Note that you can also use a function pointer instead of a lambda expression.

The above saves your notion of using foreach without complaining about an unused parameter.

+3
Jul 18 '13 at 18:39
source share

this works in GCC and clang and any compiler that supports gnu attributes:

 for( [[gnu::unused]] auto x : boost::irange(0,10) ) { 

and should compile in any C ++ 11 compiler, but cannot suppress the warning if the compiler does not recognize gnu attributes.

+1
Oct 16 '15 at 18:10
source share

To join the contest:

 #include <iostream> #include <boost/range/irange.hpp> using namespace std; using namespace boost; namespace { template<typename T> inline void unused(const T&) {} } int main() { for (auto&& i : irange(0,10)) { unused(i); cout << "Something" << endl; } return 0; } 
0
Sep 23 '19 at 19:10
source share



All Articles