31 Ocak 2018 Çarşamba

RandomAccessIterator

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.

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.
An 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
operator != metodu
Şö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;
};
Örnek
Elimizde şö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