ฉันรู้สึกว่าไม่มีคำตอบที่นี่อธิบายว่าทำไมฉันชอบ iterator เป็นแนวคิดทั่วไปมากกว่าการจัดทำดัชนีลงในภาชนะ โปรดทราบว่าประสบการณ์ส่วนใหญ่ของฉันในการใช้ตัววนซ้ำไม่ได้มาจากภาษา C ++ แต่มาจากภาษาการเขียนโปรแกรมระดับสูงเช่น Python
อินเทอร์เฟซตัววนซ้ำกำหนดข้อกำหนดที่น้อยลงสำหรับผู้บริโภคในฟังก์ชั่นของคุณซึ่งช่วยให้ผู้บริโภคสามารถทำอะไรได้มากขึ้น
หากสิ่งที่คุณต้องมีเพื่อให้สามารถส่งต่อย้ำนักพัฒนาที่ไม่ได้ จำกัด อยู่กับการใช้ภาชนะที่จัดทำดัชนี - พวกเขาสามารถใช้ชั้นใดการดำเนินการoperator++(T&)
, และoperator*(T)
operator!=(const &T, const &T)
#include <iostream>
template <class InputIterator>
void printAll(InputIterator& begin, InputIterator& end)
{
for (auto current = begin; current != end; ++current) {
std::cout << *current << "\n";
}
}
// elsewhere...
printAll(myVector.begin(), myVector.end());
อัลกอริทึมของคุณใช้ได้กับกรณีที่คุณต้องการ - วนซ้ำเวกเตอร์ - แต่มันยังมีประโยชน์สำหรับแอปพลิเคชันที่คุณไม่จำเป็นต้องคาดหมาย:
#include <random>
class RandomIterator
{
private:
std::mt19937 random;
std::uint_fast32_t current;
std::uint_fast32_t floor;
std::uint_fast32_t ceil;
public:
RandomIterator(
std::uint_fast32_t floor = 0,
std::uint_fast32_t ceil = UINT_FAST32_MAX,
std::uint_fast32_t seed = std::mt19937::default_seed
) :
floor(floor),
ceil(ceil)
{
random.seed(seed);
++(*this);
}
RandomIterator& operator++()
{
current = floor + (random() % (ceil - floor));
}
std::uint_fast32_t operator*() const
{
return current;
}
bool operator!=(const RandomIterator &that) const
{
return current != that.current;
}
};
int main()
{
// roll a 1d6 until we get a 6 and print the results
RandomIterator firstRandom(1, 7, std::random_device()());
RandomIterator secondRandom(6, 7);
printAll(firstRandom, secondRandom);
return 0;
}
ความพยายามที่จะใช้ตัวดำเนินการตัวยึดแบบเหลี่ยมซึ่งทำสิ่งที่คล้ายกับตัววนซ้ำนี้จะถูกประดิษฐ์ขึ้นในขณะที่การใช้ตัววนซ้ำนั้นค่อนข้างง่าย ตัวดำเนินการตัวยึดแบบเหลี่ยมยังสร้างความเกี่ยวกับความสามารถของชั้นเรียนของคุณซึ่งคุณสามารถทำดัชนีไปยังจุดใดก็ได้ซึ่งอาจเป็นเรื่องยากหรือไม่มีประสิทธิภาพในการใช้งาน
Iterators ยังยืมตัวให้ตกแต่ง ผู้ใช้สามารถเขียนตัววนซ้ำซึ่งใช้ตัววนซ้ำในตัวสร้างและขยายการทำงาน:
template<class InputIterator, typename T>
class FilterIterator
{
private:
InputIterator internalIterator;
public:
FilterIterator(const InputIterator &iterator):
internalIterator(iterator)
{
}
virtual bool condition(T) = 0;
FilterIterator<InputIterator, T>& operator++()
{
do {
++(internalIterator);
} while (!condition(*internalIterator));
return *this;
}
T operator*()
{
// Needed for the first result
if (!condition(*internalIterator))
++(*this);
return *internalIterator;
}
virtual bool operator!=(const FilterIterator& that) const
{
return internalIterator != that.internalIterator;
}
};
template <class InputIterator>
class EvenIterator : public FilterIterator<InputIterator, std::uint_fast32_t>
{
public:
EvenIterator(const InputIterator &internalIterator) :
FilterIterator<InputIterator, std::uint_fast32_t>(internalIterator)
{
}
bool condition(std::uint_fast32_t n)
{
return !(n % 2);
}
};
int main()
{
// Rolls a d20 until a 20 is rolled and discards odd rolls
EvenIterator<RandomIterator> firstRandom(RandomIterator(1, 21, std::random_device()()));
EvenIterator<RandomIterator> secondRandom(RandomIterator(20, 21));
printAll(firstRandom, secondRandom);
return 0;
}
แม้ว่าของเล่นเหล่านี้อาจดูธรรมดา แต่ก็ไม่ยากที่จะจินตนาการว่าการใช้ iterators และ iterator decorator ทำสิ่งที่ทรงพลังด้วยอินเตอร์เฟสที่เรียบง่าย - การตกแต่ง iterator ไปข้างหน้าอย่างเดียวของผลลัพธ์ฐานข้อมูลด้วย iterator ซึ่งสร้างวัตถุจำลองจากผลลัพธ์เดียวเช่น . รูปแบบเหล่านี้เปิดใช้งานการวนซ้ำที่ไม่มีประสิทธิภาพของหน่วยความจำและด้วยตัวกรองเช่นเดียวกับที่ฉันเขียนไว้ด้านบน
ส่วนหนึ่งของพลังของเทมเพลต C ++ คืออินเทอร์เฟซตัววนซ้ำของคุณเมื่อนำไปใช้กับอาร์เรย์ C ที่มีความยาวคงที่การสลายตัวของเลขคณิตตัวชี้ที่เรียบง่ายและมีประสิทธิภาพทำให้เป็นนามธรรมที่ไม่มีค่าใช้จ่ายอย่างแท้จริง
some_iterator++
++some_iterator
การเพิ่มภายหลังสร้างตัววนซ้ำชั่วคราวที่ไม่จำเป็น