Простые приложения на С++
January 18

Диапазоны (Ranges) в C++20

Диапазоны (Ranges) в C++20 представляют собой мощное дополнение к стандартной библиотеке, которое упрощает работу с последовательностями данных, делая код более выразительным и читаемым. Они предоставляют новый способ обработки контейнеров и других последовательностей, используя ленивую (отложенную) оценку и модульный подход.

Основные концепции и возможности диапазонов

  1. Композиция операций
    Диапазоны позволяют комбинировать операции (например, фильтрацию, трансформацию) без промежуточных контейнеров.
  2. Ленивая оценка
    Операции над диапазонами выполняются только тогда, когда это необходимо (например, при итерировании).
  3. Совместимость со стандартными контейнерами
    Диапазоны могут быть использованы с контейнерами STL (например, std::vector, std::list).
  4. Модули из <ranges>
    Все функции и классы диапазонов находятся в заголовочном файле <ranges>.
  5. Адаптеры диапазонов
    Диапазоны поддерживают адаптеры, такие как std::views::filter, std::views::transform, которые могут комбинироваться в цепочки.

Основные компоненты диапазонов

  1. std::ranges::view
    Представляет объект, который можно перебирать.
    Пример: std::views::filter, std::views::transform.
  2. std::ranges::algorithm
    Диапазоны интегрированы с алгоритмами STL, такими как std::ranges::sort, std::ranges::for_each.
  3. std::views
    Пространство имен, содержащее адаптеры представлений (views).

Примеры кода :

1. Фильтрация элементов

#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // Фильтрация четных чисел
    auto even_numbers = numbers | std::views::filter([](int n) { return n % 2 == 0; });

    // Печать результата
    for (int n : even_numbers) {
        std::cout << n << " ";
    }
    return 0;
}

2. Трансформация элементов

#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // Умножение каждого элемента на 2
    auto doubled = numbers | std::views::transform([](int n) { return n * 2; });

    for (int n : doubled) {
        std::cout << n << " ";
    }
    return 0;
}

3. Композиция операций (фильтрация + трансформация)

#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // Четные числа, умноженные на 3
    auto result = numbers 
                  | std::views::filter([](int n) { return n % 2 == 0; })
                  | std::views::transform([](int n) { return n * 3; });

    for (int n : result) {
        std::cout << n << " ";
    }
    return 0;
}

4. Диапазоны с алгоритмами std::ranges

#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>

int main() {
    std::vector<int> numbers = {5, 3, 9, 1, 4, 8};

    // Сортировка с использованием std::ranges::sort
    std::ranges::sort(numbers);

    for (int n : numbers) {
        std::cout << n << " ";
    }
    return 0;
}

5. Ограничение диапазона (Take и Drop)

#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // Взять первые 5 элементов
    auto first_five = numbers | std::views::take(5);

    // Пропустить первые 3 элемента
    auto skip_three = numbers | std::views::drop(3);

    std::cout << "First 5: ";
    for (int n : first_five) {
        std::cout << n << " ";
    }

    std::cout << "\nAfter skipping 3: ";
    for (int n : skip_three) {
        std::cout << n << " ";
    }

    return 0;
}

6. Обратный порядок (Reverse)

#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // Обратить порядок элементов
    auto reversed = numbers | std::views::reverse;

    for (int n : reversed) {
        std::cout << n << " ";
    }
    return 0;
}

7. Ленивое вычисление

Диапазоны выполняют вычисления только при необходимости.

#include <iostream>
#include <ranges>

int main() {
    auto infinite_range = std::views::iota(1); // Бесконечный диапазон от 1

    // Взять первые 10 элементов из бесконечного диапазона
    auto first_ten = infinite_range | std::views::take(10);

    for (int n : first_ten) {
        std::cout << n << " ";
    }
    return 0;
}

Итог

Диапазоны в C++20 делают код компактным, выразительным и удобным для работы с последовательностями данных. Они особенно полезны при создании "ленивых" цепочек операций, которые выполняются по мере необходимости, экономя память и ресурсы.

Телеграмм канал "Программирование игр С++/С#