Buradaki cevapların hiçbirinin, yineleyicileri neden kapsayıcılara endeksleme konusunda genel bir kavram olarak sevdiğimi açıklamamıştım. Yineleyicileri kullanma deneyimimin çoğunun aslında C ++ değil Python gibi daha üst düzey programlama dillerinden geldiğini unutmayın.
Yineleyici arabirimi, işlevinizin tüketicilerine daha az gereksinim getirir ve bu da tüketicilerin onunla daha fazlasını yapmasını sağlar.
İhtiyacınız olan tüm iletmek isteriz ki muktedir ise, geliştirici indeksli kapları kullanarak sınırlı değildir - bunlar uygulayan herhangi bir sınıf kullanabilirsiniz operator++(T&)
, operator*(T)
ve 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());
Algoritmanız ihtiyaç duyduğunuz durumda çalışır - bir vektör üzerinden yineleme - ancak mutlaka beklemediğiniz uygulamalar için de yararlı olabilir:
#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;
}
Yineleyici uygulaması nispeten basitken, bu yineleyiciye benzer bir şey yapan bir köşeli parantez operatörünün uygulanmaya çalışılması uygun olacaktır. Köşeli parantez operatörü ayrıca, uygulamanız zor veya verimsiz olabilecek sınıfınızın yetenekleri hakkında - herhangi bir keyfi noktaya indeksleyebileceğiniz - imalar yapar.
Yineleyiciler de dekorasyona borç veriyorlar . İnsanlar yapıcılarında yineleyici alan ve işlevlerini genişleten yineleyiciler yazabilir:
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;
}
Bu oyuncaklar sıradan görünse de, basit bir arayüzle güçlü şeyler yapmak için yineleyiciler ve yineleyici dekoratörleri kullandığınızı hayal etmek zor değildir - örneğin, tek bir sonuçtan bir model nesnesi oluşturan bir yineleyici ile veritabanı sonuçlarının ileriye dönük bir yineleyicisini süslemek . Bu kalıplar, sonsuz kümelerin bellek tasarruflu yinelemesini sağlar ve yukarıda yazdığım gibi bir filtreyle, sonuçların potansiyel olarak tembel olarak değerlendirilmesini sağlar.
C ++ şablonlarının gücünün bir kısmı, sabit uzunluklu C dizilerinin beğenilerine uygulandığında yineleyici arayüzünüzdür, basit ve verimli işaretçi aritmetiğine bozulur ve gerçekten sıfır maliyetli bir soyutlama yapar.
some_iterator++
için++some_iterator
. Artım sonrası gereksiz bir geçici yineleyici oluşturur.