如何使用基于范围的循环语法在STL容器中循环连续对? [英] How do I loop over consecutive pairs in an STL container using range-based loop syntax?
问题描述
如何使用基于范围的循环创建自定义类以在STL容器中循环连续的项对?
这是语法和输出I需要:
std :: list< int& number_list;
number_list.push_back(1);
number_list.push_back(2);
number_list.push_back(3);
auto paired_list = Paired(number_list);
for(const auto& pair:paired_list){
std :: printf(The pair is(%d,%d)\\\
,*(pair [0]),* pair [1]));
//或
// std :: printf(对是(%d,%d)\\\
,*(pair.first),*(pair.second)
}
//输出:
//对是(1,2)
//对是(2,3)
我知道这些(和更多)是需要的,但我不能弄清楚:
模板< class T>
class Paired {
???
class iterator {
???
}
迭代器begin(){
...
}
iterator end(){
...
}
}
不要担心 const
不要修改或复制容器中的对象。
$
#include< iterator>
#include< utility>
template< typename FwdIt> class adjacent_iterator {
public:
adjacent_iterator(FwdIt first,FwdIt last)
:m_first(first),m_next(first == last?first:std :: next(first)){}
bool operator!=(const adjacent_iterator& other)const {
return m_next!= other.m_next; // NOT m_first!
}
adjacent_iterator& operator ++(){
++ m_first;
++ m_next;
return * this;
}
typedef typename std :: iterator_traits< FwdIt> :: reference Ref;
typedef std :: pair< Ref,Ref>对;
对运算符*()const {
return Pair(* m_first,* m_next); // NOT std :: make_pair()!
}
private:
FwdIt m_first;
FwdIt m_next;
};
template< typename FwdIt> class adjacent_range {
public:
adjacent_range(FwdIt first,FwdIt last)
:m_first(first),m_last(last){}
adjacent_iterator< FwdIt> begin()const {
return adjacent_iterator< FwdIt>(m_first,m_last);
}
adjacent_iterator< FwdIt> end()const {
return adjacent_iterator< FwdIt>(m_last,m_last);
}
private:
FwdIt m_first;
FwdIt m_last;
};
template< typename C> auto make_adjacent_range(C& c) - > adjacent_range< decltype(c.begin())> {
return adjacent_range< decltype(c.begin())>(c.begin(),c.end());
}
#include< iostream>
#include< vector>
using namespace std;
void test(const vector< int>& v){
cout< [;
for(const auto& p:make_adjacent_range(v)){
cout< p.first<< /<< p.second<< ;
}
cout<< ]<< endl;
}
int main(){
test({});
test({11});
test({22,33});
test({44,55,66});
test({10,20,30,40});
}
打印:
[]
[]
[22/33]
[44/55 55/66]
[10/20 20 / 30 30/40]
注意:
-
我没有详细测试这个,但是它尊重前向迭代器(因为它不尝试使用++,!=和*之外的操作)。
/ li>
-
范围 - 要求极低;它不需要所有的前向迭代器应该提供的东西。
-
NOT m_first注释与如何接近范围的结束相关。从空范围构造的adjacent_iterator具有m_first == m_next,它也是== last。从1元素范围构造的adjacent_iterator具有指向该元素的m_first和m_next == last。从多元素范围构造的adjacent_iterator具有指向连续有效元素的m_first和m_next。当它递增时,最终m_first将指向最后一个元素,m_next将是最后一个元素。 adjacent_range的end()返回的是从(m_last,m_last)构造的。对于完全空的范围,这在物理上与begin()相同。对于1+元素范围,这在实际上不等同于已经增加的begin(),直到我们不具有完整的对 - 这样的迭代器具有指向最终元素的m_first。
-
NOT std :: make_pair()注释是因为make_pair()衰变,而我们实际上想要一对引用。 (我可以使用decltype,但iterator_traits也会告诉我们答案。)
-
主要的剩余细节将围绕禁止右值作为输入make_adjacent_range临时性的生活不会延长;委员会正在研究这个问题),并参与非成员开始/结束以及内置数组的ADL舞蹈。这些练习留给读者。
How do I create a custom class to loop over consecutive pairs of items in a STL container using a range-based loop?
This is the syntax and output I want:
std::list<int> number_list;
number_list.push_back(1);
number_list.push_back(2);
number_list.push_back(3);
auto paired_list = Paired(number_list);
for (const auto & pair : paired_list) {
std::printf("The pair is (%d, %d)\n", *(pair[0]), *(pair[1]));
// or
//std::printf("The pair is (%d, %d)\n", *(pair.first), *(pair.second));
}
// output:
// The pair is (1, 2)
// The pair is (2, 3)
I know these (and more) are needed, but I can't figure it out:
template <class T>
class Paired {
???
class iterator {
???
}
iterator begin() {
...
}
iterator end() {
...
}
}
Don't worry about const
modifiers.
No boost.
Do not modify or copy objects in the container.
Here's what I would do.
#include <iterator>
#include <utility>
template <typename FwdIt> class adjacent_iterator {
public:
adjacent_iterator(FwdIt first, FwdIt last)
: m_first(first), m_next(first == last ? first : std::next(first)) { }
bool operator!=(const adjacent_iterator& other) const {
return m_next != other.m_next; // NOT m_first!
}
adjacent_iterator& operator++() {
++m_first;
++m_next;
return *this;
}
typedef typename std::iterator_traits<FwdIt>::reference Ref;
typedef std::pair<Ref, Ref> Pair;
Pair operator*() const {
return Pair(*m_first, *m_next); // NOT std::make_pair()!
}
private:
FwdIt m_first;
FwdIt m_next;
};
template <typename FwdIt> class adjacent_range {
public:
adjacent_range(FwdIt first, FwdIt last)
: m_first(first), m_last(last) { }
adjacent_iterator<FwdIt> begin() const {
return adjacent_iterator<FwdIt>(m_first, m_last);
}
adjacent_iterator<FwdIt> end() const {
return adjacent_iterator<FwdIt>(m_last, m_last);
}
private:
FwdIt m_first;
FwdIt m_last;
};
template <typename C> auto make_adjacent_range(C& c) -> adjacent_range<decltype(c.begin())> {
return adjacent_range<decltype(c.begin())>(c.begin(), c.end());
}
#include <iostream>
#include <vector>
using namespace std;
void test(const vector<int>& v) {
cout << "[ ";
for (const auto& p : make_adjacent_range(v)) {
cout << p.first << "/" << p.second << " ";
}
cout << "]" << endl;
}
int main() {
test({});
test({11});
test({22, 33});
test({44, 55, 66});
test({10, 20, 30, 40});
}
This prints:
[ ]
[ ]
[ 22/33 ]
[ 44/55 55/66 ]
[ 10/20 20/30 30/40 ]
Notes:
I haven't exhaustively tested this, but it respects forward iterators (because it doesn't try to use operations beyond ++, !=, and *).
range-for has extremely weak requirements; it doesn't require all of the things that forward iterators are supposed to provide. Therefore I have achieved range-for's requirements but no more.
The "NOT m_first" comment is related to how the end of the range is approached. An adjacent_iterator constructed from an empty range has m_first == m_next which is also == last. An adjacent_iterator constructed from a 1-element range has m_first pointing to the element and m_next == last. An adjacent_iterator constructed from a multi-element range has m_first and m_next pointing to consecutive valid elements. As it is incremented, eventually m_first will point to the final element and m_next will be last. What adjacent_range's end() returns is constructed from (m_last, m_last). For a totally empty range, this is physically identical to begin(). For 1+ element ranges, this is not physically identical to a begin() that has been incremented until we don't have a complete pair - such iterators have m_first pointing to the final element. But if we compare iterators based on their m_next, then we get correct semantics.
The "NOT std::make_pair()" comment is because make_pair() decays, while we actually want a pair of references. (I could have used decltype, but iterator_traits will tell us the answer too.)
The major remaining subtleties would revolve around banning rvalues as inputs to make_adjacent_range (such temporaries would not have their lives prolonged; the Committee is studying this issue), and playing an ADL dance to respect non-member begin/end, as well as built-in arrays. These exercises are left to the reader.
这篇关于如何使用基于范围的循环语法在STL容器中循环连续对?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!