Can range based for loop work over a range

前端 未结 4 1028
醉梦人生
醉梦人生 2021-01-04 21:04

If I have range (pair of 2 iterators) is there a way to write \"for each\" loop for that uses range, not a raw array or container.

Something like this:



        
相关标签:
4条回答
  • 2021-01-04 21:39

    As per Why was pair range access removed from C++11? you can use an adaptor e.g. the as_range at the accepted answer, boost::make_iterator_range, or write your own:

    template<typename It> struct range {
       It begin_, end_;
       It begin() const { return begin_; }
       It end() const { return end_; }
    };
    template<typename It> range<It> as_range(const std::pair<It, It> &p) {
       return {p.first, p.second};
    }
    
    auto rng = std::equal_range(v.begin(),v.end(),1984);
    for(const auto& elem: as_range(rng))
        ...
    

    The reason this isn't applicable in general is that per Alastair Meredith's paper, of the algorithms,

    • mismatch and partition_copy return a pair of iterators from different ranges;
    • minmax returns a pair of objects that may not be iterators at all, and if they are there's no guarantee they form a range;
    • minmax_element can return a range, but it can also return a reversed range (e.g. on a reverse-sorted range minmax_element will return {prev(last), first};
    • equal_range is guaranteed to return a range.
    0 讨论(0)
  • 2021-01-04 21:45

    What std::equal_range returns is simply a std::pair. The standard doesn't cover any method to iterate over such things.

    What you may want to read is Alexandrescu's "Iterators must go" presentation. Here is the video. An excellent read on a more elegant way to iterate containers using Ranges.

    Ranges are implemented in his Loki library.

    0 讨论(0)
  • 2021-01-04 21:49

    I don't think it will work like that out of the box as equal_range returns a pair of iterators while, the for cycle over range according to documentation are:

    The begin_expr and end_expr are defined to be either:
    If (__range) is an array, then (__range) and (__range + __bound), where __bound is the array bound
    If (__range) is a class and has either a begin or end member (or both), then begin_expr is __range.begin() and end_expr is __range.end();
    Otherwise, begin(__range) and end(__range), which are found based on argument-dependent lookup rules with std as an associated namespace.
    

    I would say you may define begin and end functions that take the pair of iterators and return first and second one resepectively.

    0 讨论(0)
  • 2021-01-04 21:52
    #include <vector>
    #include <algorithm>
    #include <iostream>
    
    template <typename I>
    struct range_adapter {
        std::pair<I, I> p;
    
        range_adapter(const std::pair<I, I> &p) : p(p) {}
    
        I begin() const { return p.first; }
        I end() const { return p.second; }
    };
    
    template <typename I>
    range_adapter<I> in_range(const std::pair<I, I> &p)
    {
        return range_adapter<I>(p);
    }
    
    int main()
    {
        std::vector<int> data { 1, 2, 2, 3, 3, 3, 4 };
    
        auto r = std::equal_range(data.begin(), data.end(), 2);
    
        for (const auto &elem : in_range(r))
        {
            std::cout << elem << std::endl;
        }
    }
    
    0 讨论(0)
提交回复
热议问题