为什么从 C++11 中删除了对范围访问?

发布于 2024-11-10 08:01:41 字数 673 浏览 3 评论 0原文

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

有谁知道为什么被删除?

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

  • 基于范围的 for 循环中开始/结束的查找规则表示,开始/结束在 1) 作为范围对象的成员函数 2) 作为“关联命名空间”
  • std:: 中的自由函数进行查找pair 没有 begin/end 成员函数
  • std::pair 唯一关联的命名空间一般是命名空间 std
  • 我们不允许重载std::begin/std::end 对于 std::pair 我们自己
  • 我们不能专门化 std::begin /std::end for std::pair (因为专业化必须是部分的,并且函数不允许)

是否有其他我缺少的方法?

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 iterators as a range suitable for use in a range-based for loop (N3126, section 20.3.5.5), but this has since been removed.

Does anyone know why it was removed?

I find the removal very unfortunate, because it seems there is no other way to treat a pair of iterators as a range. Indeed:

  • The lookup rules for begin/end in a range-based for loop say that begin/end are looked for in 1) as member functions of the range object 2) as free functions in "associated namespaces"
  • std::pair does not have begin/end member functions
  • The only associated namespace for std::pair<T, U> in general is namespace std
  • 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 the specialization would have to be partial and that's not allowed for functions)

Is there some other way that I am missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

狼性发作 2024-11-17 08:01:41

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

如果您确定某对迭代器确实代表有效范围,那么您可以将它们包装到提供 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 之类的东西来手动确认这一点。

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.

め七分饶幸 2024-11-17 08:01:41

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

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.

极致的悲 2024-11-17 08:01:41

使用 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;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文