Не удалось преобразовать тип C ++ - PullRequest
1 голос
/ 06 февраля 2020

Я использую пользовательский пагинатор. Например,

vector<int> v{1,2,3,4};
for (auto page : Paginator(begin(v), end(v), 2)) {
    // For the first iteration i expect {1, 2}, and for the second {3, 4}
}

У меня есть ошибка в моем коде:

/home/alex/dev/main.cpp:32:28: error: could not convert ‘((Paginator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >*)this)->Paginator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >::data_.std::vector<_Tp, _Alloc>::begin<std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > > >, std::allocator<std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > > > > >()’ from ‘std::vector<std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > > >, std::allocator<std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > > > > >::iterator {aka __gnu_cxx::__normal_iterator<std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > > >*, std::vector<std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > > >, std::allocator<std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > > > > > >}’ to ‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’

return data_.begin();

Мой код

template<class IterT>
class Paginator {
public:
    Paginator(IterT begin, IterT end, size_t sz) {
        pageSize_ = sz;
        const size_t dist = distance(begin, end);
        parts_ = dist / pageSize_;
        if (dist % pageSize_ != 0) {
            ++parts_;
        }
        for (int i = 1; i <= parts_; ++i) {
            IterT start = next(begin, (i - 1) * pageSize_);
            IterT finish  = next(begin, i * pageSize_);
            data_.push_back({start, finish});
        }
    }

    size_t size() const {
        return parts_;
    }

    IterT begin() {
        return data_.begin();
    }

    IterT end() {
        return data_.end();
    }


private:
    size_t pageSize_;
    size_t parts_;
    vector<vector<IterT>> data_;
};

template<class T>
void Print(const vector<T>& v) {
    for (auto i : v) {
        cout << i << ' ';
    }
    cout << endl;
}

int main() {
    vector<int> v{1,2,3,4,5,6,7,8,9};


    for (auto i : Paginator<vector<int>::iterator>(begin(v), end(v), 2)) {
        Print(i);
    }
}

1 Ответ

3 голосов
/ 06 февраля 2020
IterT begin() {
    return data_.begin();
}

IterT end() {
    return data_.end();
}

vector<vector<IterT>> data_;

Тип data_.begin() - это не IterT, а std::vector<std::vector<IterT>>::iterator.

. Эти типы не конвертируются.

Простое решение - сделать begin() и end() return auto.


Ваш data_ является вектором векторов итераторов.

vector<int> v{1,2,3,4};
for (auto page : Paginator(begin(v), end(v), 2)) {
  // For the first iteration i expect {1, 2}, and for the second {3, 4}
}

здесь, page "должен" быть std::vector<std::vector<int>::iterator>. Если вы хотите, чтобы это был std::vector<int>, вам нужно переработать ваш дизайн.

    for (int i = 1; i <= parts_; ++i) {
        IterT start = next(begin, (i - 1) * pageSize_);
        IterT finish  = next(begin, i * pageSize_);
        data_.push_back({start, finish});
    }

этот код имеет проблемы с проверкой границ. Он также неэффективен для итераторов без произвольного доступа.

Он генерирует vector<IterT> с ровно 2 элементами, один начало диапазона, один конец.

Я подозреваю, что это не так то, что ты хочешь. Вам нужен vector< std::iterator_traits<IterT>::value_type >.

template<class IterT>
class Paginator {
public:
  using value_type = typename std::iterator_traits<IterT>::value_type;

  Paginator(IterT begin, IterT end, std::size_t sz):
    pageSize_(sz)
  {
    const std::size_t dist = std::distance(begin, end);
    parts_ = (dist+pageSize_-1) / pageSize_;

    for (std::size_t i = 0; i < parts_; ++i) {
      IterT start = std::next(begin, i * pageSize_);
      IterT finish  = std::next(begin, (std::min)( (i+1) * pageSize_, dist ));
      data_.emplace_back(start, finish);
    }
  }

  std::size_t size() const {
    return parts_;
  }
  auto begin() const {
    return data_.begin();
  }

  auto end() const {
    return data_.end();
  }


private:
  std::size_t pageSize_ = 0;
  std::size_t parts_ = 0;
  std::vector<std::vector<value_type>> data_;
};

Живой пример .

Если вы хотите избежать копирования, вы можете написать класс range_t это выставляет begin и end и хранит два итератора. Это позволило бы сработать тому же тестовому коду без копирования данных в структуре Paginator.

ОП содержит некоторый очевидный код , но вопрос требует .

Чтобы вышеперечисленное работало в , добавьте:

  using value_type = typename std::iterator_traits<IterT>::value_type;
  using storage = std::vector<std::vector<value_type>>;
  using iterator = typename storage::iterator;

затем

  iterator begin() const {

и

  iterator end() const {
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...