Giriş
5 tane iterator kategorisi var. Bunlar
1. input_iterator_tag - InputIterator yazısına bakınız.
2. output_iterator_tag - OutputIterator yazısına bakınız.
3. forward_iterator_tag - ForwardIterator yazısına bakınız.
4. bidirectional_iterator_tag,
5. random_access_iterator_tag - Bu yazı.
forward_iterator_tag,bidirectional_iterator_tag ve random_access_iterator_tag yapıları aynı zamanda output_iterator_tag'den kalıtır.
5 tane iterator kategorisi var. Bunlar
1. input_iterator_tag - InputIterator yazısına bakınız.
2. output_iterator_tag - OutputIterator yazısına bakınız.
3. forward_iterator_tag - ForwardIterator yazısına bakınız.
4. bidirectional_iterator_tag,
5. random_access_iterator_tag - Bu yazı.
forward_iterator_tag,bidirectional_iterator_tag ve random_access_iterator_tag yapıları aynı zamanda output_iterator_tag'den kalıtır.
Bu iterator'ün ismi C++20 ile sanırım LegacyRandomAccessIterator oldu.
ConstexprIterator Nedir?
C++20 ile ayrıca bir de ConstexprIterator. kavramı geldi. Açıklaması şöyle.
operator != metoduAn iterator can have any iterator category in addition to being ConstexprIterator.ConstexprIterator requires that all operations required by a category (that an iterator claims to conform to) work at compile-time, nothing more
Şöyle yaparız. vector random access iterator sağladığı için bu kod derlenir. Bir çok iterator != metodunu sağlar.
for (vector<int>::iterator i = vec.begin(); i != vec.end(); i++)
// DO STUFF
operator < metoduŞöyle yaparız. vector random access iterator sağladığı için bu kod derlenir. Bir çok iterator (örneğin std::list) < metodunu sağlamaz.
for (vector<int>::iterator i = vec.begin(); i < vec.end(); i++)
// DO STUFF
Nasıl TanımlanırŞöyle yaparız.
class MyIterator : public std::iterator<std::random_access_iterator_tag, double>
{
public:
MyIterator() {...}
MyIterator(const std::vector& container) : container(&container)
{...}
MyIterator(const MyIterator& rhs) = default;
MyIterator& operator = (const MyIterator& rhs) = default;
MyIterator& operator ++() {...}
MyIterator operator ++(int) {...}
MyIterator& operator --() {...}
MyIterator operator --(int) {...}
double operator *() const {...}
bool operator == (const MyIterator& rhs) const {...}
bool operator != (const MyIterator& rhs) const { return !(*this == rhs); }
private:
const std::vector<...>* container;
};
ÖrnekElimizde şöyle bir kod olsun. Bu ko belirtilen sayı kadar iterator'de atlayarak dolaşır. Uğranan eleman başa doğru kopyalanır. Böylece aradaki elemanlar silinmiş olur.
template <typename Range>
auto strided_inplace_reduce(Range& range, size_t stride) {
using std::begin;
using std::end;
using It = decltype(begin(range));
It it = begin(range), last = end(range);
return detail::strided_inplace_reduce(it, last, stride,
typename std::iterator_traits<It>::iterator_category{});
}
Çağırmak için şöyle yaparız.std::vector<int> v { 1,2,3,4,5,6,7,8,9 };
v.erase(strided_inplace_reduce(v, 2), v.end());
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout << "\nv: "," "));
Çıktı olarak şunu alırız.v: 1 3 5 7 9
Iterator tag'in göre dispatch yaparız. random_access_iterator için şöyle yaparız.namespace detail {
// version for random access iterators
template <typename It>
It strided_inplace_reduce(It it, It const last, size_t stride,
std::random_access_iterator_tag) {
It out = it;
if (stride < 1) return last;
while (it < last)
{
*out++ = *it;
std::advance(it, stride);
}
return out;
}
}
Diğer iterator tipleri için şöyle yaparız.namespace detail {
// other iterator categories
template <typename It>
It strided_inplace_reduce(It it, It const last, size_t stride, ...) {
It out = it;
if (stride < 1) return last;
while (it != last) {
*out++ = *it;
for (size_t n = stride; n && it != last; --n)
{
it = std::next(it);
}
}
return out;
}
}
Hiç yorum yok:
Yorum Gönder