ขณะนี้ฉันสามารถทำลูปตามระยะห่างได้เท่านั้น:
for (auto& value : values)
แต่บางครั้งฉันต้องการตัววนซ้ำค่าแทนการอ้างอิง (ไม่ว่าด้วยเหตุผลใดก็ตาม) มีวิธีใดบ้างที่ไม่ต้องผ่านเวกเตอร์เปรียบเทียบค่าทั้งหมด?
ขณะนี้ฉันสามารถทำลูปตามระยะห่างได้เท่านั้น:
for (auto& value : values)
แต่บางครั้งฉันต้องการตัววนซ้ำค่าแทนการอ้างอิง (ไม่ว่าด้วยเหตุผลใดก็ตาม) มีวิธีใดบ้างที่ไม่ต้องผ่านเวกเตอร์เปรียบเทียบค่าทั้งหมด?
คำตอบ:
ใช้for
ลูปเก่าเป็น:
for (auto it = values.begin(); it != values.end(); ++it )
{
auto & value = *it;
//...
}
ด้วยวิธีนี้คุณได้value
เช่นเดียวกับ it
iterator ใช้อะไรก็ได้ที่คุณต้องการใช้
แก้ไข:
แม้ว่าฉันจะไม่แนะนำสิ่งนี้ แต่ถ้าคุณต้องการใช้for
ลูปตามช่วง(ใช่ไม่ว่าจะด้วยเหตุผลใดก็ตาม : D) คุณสามารถทำได้:
auto it = std::begin(values); //std::begin is a free function in C++11
for (auto& value : values)
{
//Use value or it - whatever you need!
//...
++it; //at the end OR make sure you do this in each iteration
}
วิธีการนี้จะหลีกเลี่ยงการค้นหาที่ได้รับvalue
ตั้งแต่value
และit
อยู่เสมอในการซิงค์
std::find
หากสิ่งที่คุณต้องการคือการค้นหาค่า ... อัลกอริทึมเก่าที่ดียังอยู่ในมาตรฐานใหม่
value
และit
อาจไม่ซิงค์กัน จำไว้value
เป็นข้อมูลอ้างอิง
++it
ไปit++
เมื่อใดก็ตามที่เป็นไปได้ (ทั้งการใช้งานในรหัสของคุณ) ในขณะที่มันอาจจะมีค่าใช้จ่ายน้อยกว่า
นี่คือคลาส Wrapper ของพร็อกซีเพื่อให้คุณสามารถแสดงตัววนซ้ำที่ซ่อนอยู่ได้โดยการกำหนดนามแฝงให้กับตัวแปรของคุณเอง
#include <memory>
#include <iterator>
/* Only provides the bare minimum to support range-based for loops.
Since the internal iterator of a range-based for is inaccessible,
there is no point in more functionality here. */
template< typename iter >
struct range_iterator_reference_wrapper
: std::reference_wrapper< iter > {
iter &operator++() { return ++ this->get(); }
decltype( * std::declval< iter >() ) operator*() { return * this->get(); }
range_iterator_reference_wrapper( iter &in )
: std::reference_wrapper< iter >( in ) {}
friend bool operator!= ( range_iterator_reference_wrapper const &l,
range_iterator_reference_wrapper const &r )
{ return l.get() != r.get(); }
};
namespace unpolluted {
/* Cannot call unqualified free functions begin() and end() from
within a class with members begin() and end() without this hack. */
template< typename u >
auto b( u &c ) -> decltype( begin( c ) ) { return begin( c ); }
template< typename u >
auto e( u &c ) -> decltype( end( c ) ) { return end( c ); }
}
template< typename iter >
struct range_proxy {
range_proxy( iter &in_first, iter in_last )
: first( in_first ), last( in_last ) {}
template< typename T >
range_proxy( iter &out_first, T &in_container )
: first( out_first ),
last( unpolluted::e( in_container ) ) {
out_first = unpolluted::b( in_container );
}
range_iterator_reference_wrapper< iter > begin() const
{ return first; }
range_iterator_reference_wrapper< iter > end()
{ return last; }
iter &first;
iter last;
};
template< typename iter >
range_proxy< iter > visible_range( iter &in_first, iter in_last )
{ return range_proxy< iter >( in_first, in_last ); }
template< typename iter, typename container >
range_proxy< iter > visible_range( iter &first, container &in_container )
{ return range_proxy< iter >( first, in_container ); }
การใช้งาน:
#include <vector>
#include <iostream>
std::vector< int > values{ 1, 3, 9 };
int main() {
// Either provide one iterator to see it through the whole container...
std::vector< int >::iterator i;
for ( auto &value : visible_range( i, values ) )
std::cout << "# " << i - values.begin() << " = " << ++ value << '\n';
// ... or two iterators to see the first incremented up to the second.
auto j = values.begin(), end = values.end();
for ( auto &value : visible_range( j, end ) )
std::cout << "# " << j - values.begin() << " = " << ++ value << '\n';
}
ฉันลองทำด้วยตัวเองและพบวิธีแก้ปัญหา
การใช้งาน:
for(auto i : ForIterator(some_list)) {
// i is the iterator, which was returned by some_list.begin()
// might be useful for whatever reason
}
การนำไปใช้นั้นไม่ยาก:
template <typename T> struct Iterator {
T& list;
typedef decltype(list.begin()) I;
struct InnerIterator {
I i;
InnerIterator(I i) : i(i) {}
I operator * () { return i; }
I operator ++ () { return ++i; }
bool operator != (const InnerIterator& o) { return i != o.i; }
};
Iterator(T& list) : list(list) {}
InnerIterator begin() { return InnerIterator(list.begin()); }
InnerIterator end() { return InnerIterator(list.end()); }
};
template <typename T> Iterator<T> ForIterator(T& list) {
return Iterator<T>(list);
}
boost::counting_iterator
แม้ว่าจะมีสิ่งที่ทำอย่างนั้นและถูกห่อด้วยอย่างสะดวกboost::counting_range
ดังนั้นคุณสามารถเขียน: for(auto it : boost::counting_range(r.begin(), r.end()))
. :)
operator++()
ควรกลับมาเป็นInnerIterator
อย่างอื่นที่ดีและน่าเกลียดมาก
for
ลูปตามช่วงถูกสร้างขึ้นเป็นคู่ c ++ สำหรับforeach
ใน java ซึ่งช่วยให้สามารถทำซ้ำองค์ประกอบอาร์เรย์ได้ง่าย มีไว้สำหรับการลบการใช้โครงสร้างที่ซับซ้อนเช่นตัวทำซ้ำเพื่อให้ง่าย ฉันต้องการiterator
อย่างที่นาวาซบอกคุณจะต้องใช้for
ลูปปกติ
for
คือน้ำตาลไวยากรณ์และการลดปริมาณการพิมพ์ การต้องหักล้างตัวทำซ้ำจะทำให้เกิดข้อผิดพลาดได้ง่ายโดยเฉพาะเมื่อใช้กับauto
มีวิธีง่ายๆในการทำสิ่งนี้std::vector
ซึ่งควรได้ผลเช่นกันหากคุณกำลังปรับขนาดเวกเตอร์ในระหว่างกระบวนการ (ฉันไม่แน่ใจว่าคำตอบที่ยอมรับจะพิจารณากรณีนี้หรือไม่)
ถ้าb
เป็นเวกเตอร์ของคุณคุณก็ทำได้
for(auto &i:b){
auto iter = b.begin() + (&i-&*(b.begin()));
}
ที่iter
จะเป็นตัวทำซ้ำที่คุณต้องการ
นี้ใช้ประโยชน์จากความจริงที่ว่าC ++ เวกเตอร์ที่ต่อเนื่องกันอยู่เสมอ
vector<T>::iterator
ไปT*
: ตรวจสอบว่ามีแล้วก็ใช้static_assert()
T* iter = &i;
ลองทำดูสกปรกมาก ... ฉันรู้ว่า 0x70h กำลังเปลี่ยนไปตามการใช้งานสแต็กเวอร์ชันคอมไพเลอร์ .... คอมไพเลอร์ควรเปิดเผย แต่มันไม่ใช่ :-(
char* uRBP = 0; __asm { mov uRBP, rbp }
Iterator** __pBegin = (Iterator**)(uRBP+0x70);
for (auto& oEntry : *this) {
if (oEntry == *pVal) return (*__pBegin)->iPos;
}