Как расширить функциональность векторного класса и его итератора C ++ - PullRequest
0 голосов
/ 29 мая 2020

Я хотел бы найти чистый способ немного изменить способ работы std :: vector.

Фон проблемы

Мне нужно иметь индекс в векторе, где указатель по существу сдвинется на один назад, например; если мой вектор содержит {0,1,2,3,4,5} и индекс [3] должен проскользнуть, при итерации по вектору он должен вернуть: 0, 1, 2, 3, 3, 4, 5

Проблема

Можно ли без перезаписи всего векторного класса и реализации моих изменений унаследовать std::vector<T> в настраиваемый класс и переопределить поведение итераторов ++ оператор, а также вектор :: begin ()? (чтобы добавить памяти о том, что он уже соскользнул, и чтобы не поскользнуться снова)

То, что я пробовал

До сих пор я пробовал в основном реализацию, но застряли при попытке переопределить функцию begin ().

#include <vector>
#include <iostream>
#include <iterator>

template <typename T>
class myVector : public std::vector<T>{
public:
  class myIterator : public std::vector<T>::iterator
  {
    // call vector's iterotor constructor

    //override
    // iterator& operator++(void){}
    // iterator operator++(int){}
  };

  using std::vector<T>::vector; // use the constructor from vector

  // extend the begin function, but include original operation
  myVector::myIterator begin() const
  {
    std::cout << "hi\n"; // testing to see if begin has been overriden properly
    return std::vector<T>::begin();
  }

};

// print out the vector
template <typename T> 
std::ostream& operator<<(std::ostream& os, const myVector<T>& v) 
{ 
  auto begin=v.begin();
  while (begin!=v.end())
  {
    os << *begin;
    ++begin;

    if(begin!=v.end())
    {
      os << ',';
    }
  }
  return os;
} 

int main() {
  myVector<int> vec = {1,2,3,4};

  std::cout << vec << '\n';
}

Если у вас есть альтернативные чистые решения, это тоже приветствуется.

Спасибо

Ответы [ 2 ]

4 голосов
/ 29 мая 2020

Я бы никогда не унаследовал std::vector публично. Его слишком легко использовать неправильно, и у вас нет контроля над неправильным использованием. std::vector не имеет виртуального деструктора!

Итераторы кажутся подходящей точкой настройки. Для получения полностью совместимого итератора требуется гораздо больше, но этого достаточно для рабочего примера:

#include <iterator>
#include <vector>
#include <iostream>

template <typename It>
struct slippery_iterator {
    bool slipped = false;
    It to_be_repeated;
    It iterator;
    slippery_iterator(It iterator,It to_be_repeated) : iterator(iterator),to_be_repeated(to_be_repeated){}

    slippery_iterator& operator++(){
        if (!slipped && iterator == to_be_repeated){
            slipped = true;
            return *this;
        }        
        ++iterator;        
        return *this;
    }
    typename std::iterator_traits<It>::reference operator*(){
        return *iterator;
    }
    bool operator!=(It other) { return iterator != other;}
};

template <typename It>
slippery_iterator<It> make_slippery_iterator(It it,It slip){
    return {it,slip};
}


int main() {
    std::vector<int> x{1,2,3,4,5};
    auto begin = make_slippery_iterator(x.begin(),x.begin()+2);
    for (; begin != x.end(); ++begin){
        std::cout << *begin;
    }
}

Вывод:

123345

PS: Обратите внимание, что я привык к C + +11, где нужен помощник make_x. Это не требуется для более новых стандартов.

1 голос
/ 29 мая 2020

Как уже говорили другие, просто определите собственный итератор. Если вам, кроме того, нужна хорошая итерация диапазона, вы можете просто определить класс настраиваемого диапазона, возвращающий ваши настраиваемые итераторы.

См. Рабочий пример ниже (требуется --std = c ++ 17):

#include <vector>
#include <iostream>

template<typename T>
class SlipIterator {
private:
  using iterator = typename std::vector<T>::const_iterator;
  iterator i;
  iterator slip;
  bool has_slipped;

public:
  SlipIterator(iterator i, iterator slip): i(i), slip(slip), has_slipped(false) {}

  SlipIterator &operator++() {
    if ((!has_slipped) && (i == slip))
      has_slipped = true;
    else
      ++i;
    return *this;
  }

  bool operator!=(SlipIterator<T> &the_end) const { return i != the_end.i; }

  const T &operator*() const { return *i; }

};

template<typename T>
class SlipperyRange {
private:
  const std::vector<T> &v;
  size_t slip_index;

public:
  SlipperyRange(const std::vector<T> &v, size_t slip_index) : v(v), slip_index(slip_index) {}

  SlipIterator<T> begin() const { return SlipIterator<T>(v.cbegin(), v.cbegin() + slip_index); }

  SlipIterator<T> end() const { return SlipIterator<T>(v.cend(), v.cend()); }
};

int main() {
  std::vector<int> v{1,2,3,4,5};
  for(const int i: SlipperyRange{v, 2})
    std::cout << i << ' ';
  std::cout << '\n';
  return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...