Skipping in Range-based for based on 'index'?

后端 未结 7 1315
一向
一向 2021-01-02 01:10

Is there a way to access the iterator (suppose there\'s no loop index..?) in a C++11 range-based for loop?

Often we need to do something special with the fi

相关标签:
7条回答
  • 2021-01-02 01:53

    No, you can't get the iterator in a range-based for loop (without looking up the element in the container, of course). The iterator is defined by the standard as being named __begin but this is for exposition only. If you need the iterator, it is intended that you use the normal for loop. The reason range-based for loop exists is for those cases where you do not need to care about handling the iteration yourself.

    With auto and std::begin and std::end, your for loop should still be very simple:

    for (auto it = std::begin(container); it != std::end(container); it++)
    
    0 讨论(0)
  • 2021-01-02 01:59

    Often we need to do something special with the first element of a container and iterate over the remaining elements.

    I am surprised to see that nobody has proposed this solution so far:

      auto it = std::begin(container);
    
      // do your special stuff here with the first element
    
      ++it;
    
      for (auto end=std::end(container); it!=end; ++it) {
    
          // Note that there is no branch inside the loop!
    
          // iterate over the rest of the container
      }
    

    It has the big advantage that the branch is moved out of the loop. It makes the loop much simpler and perhaps the compiler can also optimize it better.

    If you insist on the range-based for loop, maybe the simplest way to do it is this (there are other, uglier ways):

    std::size_t index = 0;
    
    for (auto& elem : container) {
    
      // skip the first element
      if (index++ == 0) {
         continue;
      }
    
      // iterate over the rest of the container
    }
    

    However, I would seriously move the branch out of the loop if all you need is to skip the first element.

    0 讨论(0)
  • 2021-01-02 02:07

    When I need to do something like this on a random access container, my habit is to iterate over the indexes.

    for( std::size_t i : indexes( container ) ) {
      if (i==0) continue;
      auto&& e = container[i];
      // code
    }
    

    the only tricky part is writing indexes, which returns a range of what boost calls counting iterators. Creating a basic iterable range from iterators is easy: either use boost's range concept, or roll your own.

    A basic range for an arbitrary iterator type is:

    template<typename Iterator>
    struct Range {
      Iterator b; Iterator e;
      Range( Iterator b_, Iterator e_ ):b(b_), e(e_) {};
      Iterator begin() const { return b; }
      Iterator end() const { return e; }
    };
    

    which you can gussy up a bunch, but that is the core.

    0 讨论(0)
  • 2021-01-02 02:10

    When iterating over elements, always prefer to use an algorithm, and use a plain for loop only if none of the algorithms fit.

    Picking the right algorithm depends on what you want to do with the elements... which you haven't told us.

    If you want to skip the first element, dump example:

    if (!container.empty()) {
       for_each(++container.begin(), container.end(), [](int val) { cout << val; });
    }
    
    0 讨论(0)
  • 2021-01-02 02:10

    How about using a simple for loop with iteratos:

    for(auto it = container.begin(); it != container.end(); it++)
    {
        if(it == container.begin())
        {
            //do stuff for first
        }
        else
        {
            //do default stuff
        }
    }
    

    It's not range based, but it's functional. In case you may still want to use the range loop:

    int counter = 0;
    for(auto &data: container)
    {
        if(counter == 0)
        {
            //do stuff for first
        }
        else
        {
            //do default stuff
        }
        counter++;
    }
    
    0 讨论(0)
  • 2021-01-02 02:13

    There is no way of knowing how far an element is within the container without having an iterator, pointer or an intrusive index. Here's a simple way of doing it:

    int index= 0;
    for (auto& elem: container) 
    {
      if (index++ == something)
         continue;
    
      // do something with remaining elements
    }
    

    If you want to skip the first element, another way is to use a std::deque and pop_front the first element. Then you can do your ranged for loop with the container as usual.

    0 讨论(0)
提交回复
热议问题