TGViewer
Библиотека C/C++ разработчика | cpp, boost, qt Библиотека C/C++ разработчика | cpp, boost, qt @cppproglib · 16.9K subscribers
Post #6813 1.36K
🐞 Собственный View-адаптер

Настоящий View в C++20 должен наследовать от std::ranges::view_base или std::ranges::view_interface<T>. Давайте создадим практический пример — stride_view, который пропускает элементы диапазона с заданным шагом.


🥝 Наследование от view_interface

Любой приличный view должен наследоваться от std::ranges::view_interface<T>. Это даёт тебе begin(), end(), size() и прочие плюшки бесплатно.

template<std::ranges::input_range R>
class stride_view : public std::ranges::view_interface<stride_view<R>> {
private:
// Если R уже view, используем R. Иначе — ref_view для безопасности
R base_;
std::ranges::range_difference_t<R> stride_;

public:
stride_view() = default;

stride_view(R base, std::ranges::range_difference_t<R> stride)
: base_(std::move(base)), stride_(stride) {
// Критическая проверка: stride должен быть положительным!
if (stride_ <= 0) {
throw std::invalid_argument("stride must be > 0");
}
}

auto begin() {
return stride_iterator<R>{ std::ranges::begin(base_),
std::ranges::end(base_), stride_ };
}

auto begin() const {
return stride_iterator<R>{ std::ranges::begin(base_),
std::ranges::end(base_), stride_ };
}

auto end() {
return stride_sentinel<R>{};
}

auto end() const {
return stride_sentinel<R>{};
}
};


😏 Видишь? Сохраняем базовый диапазон и размер шага. Дальше — только логика в итераторе.


☝️ Как работает stride_iterator и stride_sentinel

Итератор — это сердце view. На каждый operator++() он прыгает на stride_ позиций вперёд, не переходя за конец диапазона:

template<std::ranges::input_range R>
struct stride_sentinel {};

template<std::ranges::input_range R>
struct stride_iterator {
std::ranges::iterator_t<R> current_;
std::ranges::sentinel_t<R> end_;
std::ranges::range_difference_t<R> stride_;

// Pre-increment: ++it
stride_iterator& operator++() {
// 🔴 Критический момент: проверяем, не за пределами ли мы
for (int i = 0; i < stride_ && current_ != end_; ++i) {
++current_;
}
return *this;
}

// Post-increment: it++
stride_iterator operator++(int) {
auto tmp = *this;
++(*this);
return tmp;
}

auto operator*() const {
return *current_;
}

// Сравнение с концом диапазона через sentinel
bool operator==(const stride_sentinel<R>&) const {
return current_ == end_;
}
};


☝️ Почему sentinel? Потому что begin() и end() могут быть разных типов в C++20 ranges. Это позволяет избежать ошибки типов при сравнении.


⚡️ Пример использования

std::vector v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto strided = stride_view(v, 2);

for (auto x : strided) {
std::cout << x << " "; // 0 2 4 6 8
}


👌 Красиво: не создали новый вектор, просто гуляем по старому с шагом 2. Никакого копирования, только ленивые вычисления!


⚠️ Замечание: В C++23 это уже есть!

for (auto x : v | std::views::stride(2)) {
std::cout << x << " "; // 0 2 4 6 8
}


🫰 std::views::stride уже входит в стандартную библиотеку! Пример выше — исключительно учебный


📍Навигация: ВакансииЗадачи Собесы

Библиотека C/C++ разработчика

#константная_правильность
  • ❤ 3
  • 🔥 1
  • 👾 1
More from @cppproglib
  1. Sep 19, 2026А вы уже забрали свой подарок ко Дню программиста? К вашему профессиональному празднику Tp…
  2. Sep 18, 2026Сегодня последний день регистрации на КосмоХакатон! 18–20 сентября, Петербург, Красноярск…
  3. Sep 18, 2026От исходного кода до процессора: разберись, как работает программа 💻 Стартует практически…
  4. Sep 15, 2026😭 Как не потратить недельный лимит AI-кодинга за три дня? Разберём на вебинаре, как трати…
  5. Sep 13, 2026🤪 Если бы можно было задать один вопрос про AI в разработке — что бы вы спросили? Как выб…
  6. Sep 13, 2026🤩 Inline static в классах — забудь про .cpp Сколько раз ты забывал добавить определение s…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →