Why was access to pairs removed from C ++ 11?

I just discovered that at some point the C ++ 11 project had std::begin / std::end overloads for std::pair , which allowed us to treat a couple of iterators as a range, suitable for use in a range-based loop ( N3126, section 20.3.5.5), but it has since been deleted.

Does anyone know why it was deleted?

I find the removal very unfortunate because there seems to be no other way to treat a pair of iterators as a range. Really:

  • The search rules for start / end in a range-based loop say that start / end is considered 1) as member functions of a range object 2) as free functions in "related namespaces"
  • std::pair does not have element start / end functions
  • The only related namespace for std::pair<T, U> is generally the std namespace
  • We are not allowed to overload std::begin / std::end for std::pair ourselves
  • We cannot specialize std::begin / std::end for std::pair (because specialization should be partial and not allowed for functions)

Is there any other way that I am missing?

+52
c ++ foreach c ++ 11 range std-pair
May 29 '11 at 11:55
source share
3 answers

I think the 2009 article, β€œCouples Don't Make Good Ranges,” Alisdair Meredith is at least part of the answer. In principle, many algorithms return pairs of iterators that are not really guaranteed to be valid ranges. For this reason, for this reason they removed support for pair<iterator,iterator> from the for-range loop. However, the proposed solution was not fully adopted.

If you know for sure that some pair of iterators really represents a valid range, you can bind them to a custom type that the begin () / end () member functions offer:

 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))) { ... } } 

(unverified)

I agree that this is a little wart. Functions that return valid ranges (e.g. equal_range) should say this using the appropriate return type. It is a little confusing that we have to manually confirm this with something like as_range above.

+38
May 30 '11 at 11:47
source share

You can use boost::make_iterator_range . It creates an iterator_range method with begin() and end() methods. boost::make_iterator_range can take std::pair iterators.

+8
Apr 22 '15 at 14:46
source share

extending the above answer using C ++ 11 optimization:

 #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; } 
+6
Apr 22 '14 at 15:08
source share



All Articles