Ежедневный бит (e) C++ # 136, индексированное представление C++ 23: std::views::enumerate.

Range-for-loop — это очень удобная замена цикла for в стиле C.

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

C++23 std::views::enumerate устраняет эту проблему, создавая диапазон кортежей, где i-й кортеж состоит из значения i и ссылку на i-й элемент исходного диапазона.

#include <vector>
#include <ranges>


std::vector<int> data{1, 2, 3, 4, 5, 6, 7};

// Applying enumerate before other views to inject original indexes
constexpr auto before = std::views::enumerate | 
    std::views::filter([](auto t) {
        return std::get<1>(t) % 2 == 0;
    });
for (auto [idx, value] : data | before) {
    // Iterate over: {1,2}, {3,4}, {5,6}
}

// Applying enumerate after other views to index the resuling range
constexpr auto after = std::views::filter([](int v) { 
    return v % 2 == 0;
}) | std::views::enumerate;
for (auto [idx, value] : data | after) {
    // Iterate over: {0,2}, {1,4}, {2,6}
}

// Since the second element of the tuple is a reference,
// we maintain mutability
for (auto [idx, value] : data | std::views::enumerate) {
    value -= idx;
}
// data == {1,1,1,1,1,1,1}

Откройте пример в Compiler Explorer.