C++11: Range-looping vector from the second element?

前端 未结 2 416
天命终不由人
天命终不由人 2020-12-19 04:27

I have a std::vector v; (initialized). How can I use the range-for loop for accessing all elements except the first one (on index zero). For

相关标签:
2条回答
  • 2020-12-19 04:54

    Create a wrapper for which begin() and end() return the correct iterators and then you can use that as the second argument.

    #include <iostream>
    #include <vector>
    
    template< typename Collection >
    class FromNth
    {
        Collection& coll_;
        size_t offset_;
    
    public:
        FromNth( Collection& coll, size_t offset )
            : coll_( coll ), offset_( offset )
        {
        }
    
        // will nicely resolve to const_iterator if necessary
        auto begin() const -> decltype( coll_.begin() ) 
           { return coll_.begin() + offset_; }
    
        auto end() const -> decltype( coll_.end() )
           { return coll_.end(); }
    };
    
    template< typename Collection >
    FromNth<Collection> makeFromNth( Collection& collection, size_t offset )
    {
         return FromNth<Collection>( collection, offset );
    }
    
    template< typename Collection >
    auto begin( const FromNth<Collection> & wrapper ) -> decltype( wrapper.begin() )
    {   
       return wrapper.begin();
    }
    
    template< typename Collection >
    auto end( const FromNth<Collection> & wrapper ) -> decltype( wrapper.end() )
    {  
       return wrapper.end();
    }
    
    int main()
    {
       std::vector< int > coll { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
    
       for( auto x : makeFromNth( coll, 1 ) )
       {
           std::cout << x << '\n';
       }
       return 0;
    }
    

    Note that my fromNth "begin" is undefined behaviour if the size of the input is less than the offset. (If it's equal then it's well defined and begin == end). Therefore do a size check first.

    Note: if you are using a recent enough version of boost then iterator_range may already provide you such a "collection" that is similar to my "FromNth".

    for( auto const& s : boost::make_iterator_range( v.begin() + 1, v.end() ) )
    {
        process( s );
    }
    

    Note: the code above worked on CodingGround using C++11 GNU 4.8.3. (That site is very slow though). From C++14 you will not need the ->decltype statements (which are needed in C++11 for templates).

    Output:

    sh-4.3$ g++ -std=c++11 -o main *.cpp
    sh-4.3$ main
    3
    5
    7
    11
    13
    17
    19
    23 
    
    0 讨论(0)
  • 2020-12-19 04:58

    Until ranges make it into the standard library, you won't get any better than a vanilla for loop in plain C++ :

    for(auto i = begin(v) + 1, e = end(v); i !=e; ++i)
        // Do something with *i
    
    0 讨论(0)
提交回复
热议问题