Testing whether an iterator points to the last item?

前端 未结 9 895
旧巷少年郎
旧巷少年郎 2020-12-23 11:31

I have an stl iterator resulting from a std::find() and wish to test whether it is the last element. One way to write this is as follows:

mine *match = some         


        
相关标签:
9条回答
  • 2020-12-23 12:30

    You would first need a way to determine if an iterator is a reverse one, which was ingeniously shown here :

    #include <iterator>
    #include <type_traits>
    
    template<typename Iter>
    struct is_reverse_iterator : std::false_type { };
    
    template<typename Iter>
    struct is_reverse_iterator<std::reverse_iterator<Iter>>
    : std::integral_constant<bool, !is_reverse_iterator<Iter>::value>
    { };
    

    Then you could have two flavors for performing the test

    template<bool isRev> // for normal iterators
    struct is_last_it
    {
        template<typename It, typename Cont>
        static bool apply(It it, Cont const &cont)
        { // you need to test with .end()
            return it != cont.end() && ++it == cont.end();
        }
    };
    
    template<> // for reverse iterators
    struct is_last_it<true>
    {
        template<typename It, typename Cont>
        static bool apply(It it, Cont const &cont)
        { // you need to test with .rend()
            return it != cont.rend() && ++it == cont.rend();
        }
    };
    

    And a single interface function

    template<typename It, typename Cont>
    bool is_last_iterator(It it, Cont const &cont)
    {
        return is_last_it<is_reverse_iterator<It>::value>::apply(it, cont);
    };
    

    Then for every type of iterator (reverse / straight) you can use the interface function

    int main()
    {
        std::vector<int> v;
        v.push_back(1);
    
        auto it (v.begin()),  ite(v.end());   // normal iterators
        auto rit(v.rbegin()), rite(v.rend()); // reverse iterators
    
        std::cout << is_last_iterator(it, v) << std::endl;
        std::cout << is_last_iterator(ite, v) << std::endl;
        std::cout << is_last_iterator(rit, v) << std::endl;
        std::cout << is_last_iterator(rite, v) << std::endl;
    
        return 0;
    }
    

    Note that some implementation (apart from std::begin() and std::end() which are common enough, also include std::rbegin() and std::rend(). When possible use this set of functions instead of member .begin() etc.

    0 讨论(0)
  • 2020-12-23 12:32

    Here's another potential solution:

    template<class Iterator, class Container> bool is_last(Iterator it, const Container& cont)
    {
        // REQUIREMENTS:
        // the iterator must be a valid iterator for `cont`
        if( it == cont.end() )
            return false;   // or throw if you prefer
        return (++it) == cont.end();
    }
    
    0 讨论(0)
  • 2020-12-23 12:36

    A better way would be to copy the iterator and then increment it. You can then test the incremented version against end(). If you're careful, you can use a post-increment to avoid the need to formally copy it.

      if (++vector<mine*>::iterator(itr) == Mine.end())
    

    If itr could already be at the end:

      if (itr == Mine.end() || ++vector<mine*>::iterator(itr) == Mine.end())
    

    Or, based on GMan's answer but a bit safer:

      if (Mine.Length() == 0 || itr == Mine.End() || &*itr == &Mine.back())
    

    I just fixed the last one again, as I was wrong about &*.

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