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

前端 未结 10 1041
轮回少年
轮回少年 2020-12-24 04:33

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         


        
相关标签:
10条回答
  • 2020-12-24 05:07

    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 讨论(0)
  • 2020-12-24 05:15

    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.

    0 讨论(0)
  • 2020-12-24 05:18

    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.

    0 讨论(0)
  • 2020-12-24 05:19

    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.

    0 讨论(0)
  • 2020-12-24 05:20

    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.

    0 讨论(0)
  • 2020-12-24 05:23

    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:

    • an array or
    • a class having either
      • Member functions begin() and end() or
      • available free functions begin() 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();
    
    0 讨论(0)
提交回复
热议问题