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 her
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;
}
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
.
this works in GCC and clang and any compiler that supports the gnu attributes:
for( [[gnu::unused]] auto x : boost::irange(0,10) ) {
and should compile in any c++11 compiler but may not suppress the warning if the compiler doesn't recognise the gnu attributes.
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.
Already best answered in https://stackoverflow.com/a/21800058/1147505 : how to define an UNUSED macro to be used throughout your codebase, which suppresses this warning. In a portable way.
There isn't any way to make a range based for work for simply iterating over several numbers.
C++11 range-based loops require a ranged expression which may be:
begin()
and end()
orbegin()
and end()
(via ADL)In addition to that: A range based for produces some overhead:
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 via array inspection or begin()
/ end()
pairs.
I don't think this gets any "cleaner" than a simple for-loop. Especially with respect to performance. No calls, just a plain loop.
The only way I can figure out to make it more elegant (where elegant is clearly subject to my opinion) is by using a size or unsigned type here:
for(size_t x(0U); x<10U; ++x) f();