Why was pair range access removed from C++11?

前端 未结 3 725
半阙折子戏
半阙折子戏 2020-12-02 12:08

I just discovered that at one point, the C++11 draft had std::begin/std::end overloads for std::pair that allowed treating a pair of i

相关标签:
3条回答
  • 2020-12-02 12:34

    You can use boost::make_iterator_range. It constructs an iterator_range with begin() and end() methods. boost::make_iterator_range can accept std::pair of iterators.

    0 讨论(0)
  • 2020-12-02 12:35

    I think the 2009 paper "Pairs do not make good ranges" by Alisdair Meredith is at least part of the answer. Basically, many algorithms return pairs of iterators that are actually not guaranteed to be valid ranges. It seems they removed the support for pair<iterator,iterator> from the for-range loop for this reason. However, the proposed solution has not been fully adopted.

    If you know for certain that some pair of iterators really represents a valid range then you could wrap them into a custom type which offers begin()/end() member functions:

    template<class Iter>
    struct iter_pair_range : std::pair<Iter,Iter> {
        iter_pair_range(std::pair<Iter,Iter> const& x)
        : std::pair<Iter,Iter>(x)
        {}
        Iter begin() const {return this->first;}
        Iter end()   const {return this->second;}
    };
    
    template<class Iter>
    inline iter_pair_range<Iter> as_range(std::pair<Iter,Iter> const& x)
    { return iter_pair_range<Iter>(x); }
    
    int main() {
        multimap<int,int> mm;
        ...
        for (auto& p : as_range(mm.equal_range(42))) {
           ...
        }
    }
    

    (untested)

    I agree this is a bit of a wart. Functions which return valid ranges (like equal_range) should say so using an appropriate return type. It's a bit embarrasing that we have to manually confirm this via something like as_range above.

    0 讨论(0)
  • 2020-12-02 12:37

    expanding on the above answer using c++11 optimisations:

    #include <utility>
    
    template<class Iter>
    struct range_t : public std::pair<Iter, Iter> {
        using pair_t = std::pair<Iter, Iter>;
        range_t(pair_t&& src)
        : std::pair<Iter, Iter>(std::forward<pair_t>(src))
        {}
    
        using std::pair<Iter, Iter>::first;
        using std::pair<Iter, Iter>::second;
    
        Iter begin() const { return first; }
        Iter end() const { return second; }
    };
    
    template<class Iter>
    range_t<Iter> range(std::pair<Iter, Iter> p) {
        return range_t<Iter>(std::move(p));
    }
    
    template<class Iter>
    range_t<Iter> range(Iter i1, Iter i2) {
        return range_t<Iter>(std::make_pair(std::move(i1), std::move(i2)));
    }
    
    
    // TEST: 
    
    #include <iostream>
    #include <set>
    using namespace std;
    
    int main() {
    
        multiset<int> mySet { 6,4,5,5,5,3,3,67,8,89,7,5,45,4,3 };
    
        cout << "similar elements: ";
        for (const auto&i : range(mySet.lower_bound(5), mySet.upper_bound(10))) {
            cout << i << ",";
        }
        cout << "\n";
    
        int count = 0, sum = 0;
        for (const auto& i: range(mySet.equal_range(5)))
        {
            ++count;
            sum += i;
        }
        cout << "5 appears " << count << " times\n"
        << "the sum is " << sum << "\n";
    
    return 0;
    }
    
    0 讨论(0)
提交回复
热议问题