55

我刚刚发现,在某个时刻,C++11 草案有std::begin/std::end重载std::pair允许将一对迭代器视为适合在基于范围的 for 循环中使用的范围(N3126,第 20.3.5.5 节),但这有自从被删除。

有谁知道它为什么被删除?

我发现删除非常不幸,因为似乎没有其他方法可以将一对迭代器视为一个范围。确实:

  • 在基于范围的 for 循环中查找开始/结束的规则表明,开始/结束在 1) 中作为范围对象的成员函数 2) 作为“关联命名空间”中的自由函数进行查找
  • std::pair没有开始/结束成员函数
  • 通常,唯一关联的命名空间std::pair<T, U>是命名空间 std
  • 我们不允许超载std::begin/std::endstd::pair自己
  • 我们不能专门化std::begin/ std::endfor std::pair(因为专门化必须是部分的,而函数不允许这样做)

还有其他我想念的方式吗?

4

3 回答 3

43

我认为 Alisdair Meredith 的 2009 年论文“Pairs do not make good range”至少是部分答案。基本上,许多算法返回实际上不能保证是有效范围的迭代器对。出于这个原因,他们似乎pair<iterator,iterator>从 for-range 循环中删除了对的支持。然而,提议的解决方案并未被完全采用。

如果您确定某些迭代器确实代表了一个有效范围,那么您可以将它们包装成提供 begin()/end() 成员函数的自定义类型:

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

(未经测试)

我同意这有点像疣。返回有效范围的函数(如 equal_range)应该使用适当的返回类型来说明。有点尴尬,我们必须通过类似as_range上面的方式手动确认这一点。

于 2011-05-30T11:47:45.583 回答
9

您可以使用boost::make_iterator_range. begin()它使用和end()方法 构造一个 iterator_range 。boost::make_iterator_range可以接受std::pair迭代器。

于 2015-04-22T14:46:39.257 回答
6

使用 c++11 优化扩展上述答案:

#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;
}
于 2014-04-22T15:08:58.160 回答