C++20 memperkenalkan Ranges Library — abstraksi di atas iterator yang memungkinkan komposisi algoritma secara deklaratif. Alih-alih menulis loop bertingkat atau beberapa pass dengan iterator, kita dapat menulis pipeline seperti v | filter | transform | take(3). Ranges bersifat lazy — elemen diproses saat diiterasi, sehingga komposisi beberapa view tidak menghasilkan container intermediate. Pada Chapter ini kita akan mendemonstrasikan komposisi dengan std::views dan std::ranges::* algorithm — disarankan mengkompilasi dengan g++ -std=c++20.
Dua Komponen Utama #
| Komponen | Fungsi |
|---|---|
std::ranges::* | Versi algoritma STL yang menerima range (bukan pasangan iterator) — ranges::sort(v), ranges::find(v, x), ranges::min(v). |
std::views::* | Adaptor yang menghasilkan view — range lazily evaluated yang tidak menyalin data. |
View adalah pair (underlying range + transformasi). Saat diiterasi, view meminta elemen dari underlying range satu per satu, menerapkan transformasi, lalu mengembalikan hasil.
Mekanisme: Lazy Evaluation #
Kode v | views::filter(p) | views::transform(f) | views::take(3) tidak memproses elemen apapun saat deklarasi. Hanya saat iterasi (for (auto x : hasil)), pipeline dimulai:
take(3)meminta satu elemen daritransform.transformmeminta satu elemen darifilterdan menerapkanf.filtermeminta elemen darivsatu per satu sampai menemukan yang memenuhi predikatp.- Proses berulang sampai
take(3)terpenuhi.
Akibatnya: bila v berukuran sejuta elemen tetapi hanya tiga yang lolos filter, pipeline hanya memproses elemen yang diperlukan. Tidak ada alokasi container intermediate.
Kode: Pipeline dengan Views #
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 1) views::filter — hanya elemen genap
auto genap = v | std::views::filter([](int x) { return x % 2 == 0; });
std::cout << "filter genap : ";
for (int x : genap) std::cout << x << ' ';
std::cout << '\n';
// 2) views::transform — kalikan 10
auto kali10 = v | std::views::transform([](int x) { return x * 10; });
std::cout << "transform x10 : ";
for (int x : kali10) std::cout << x << ' ';
std::cout << '\n';
// 3) Pipeline: filter genap -> transform x10 -> take 3
auto hasil = v
| std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * 10; })
| std::views::take(3);
std::cout << "pipeline : ";
for (int x : hasil) std::cout << x << ' ';
std::cout << '\n';
// 4) views::take / drop
auto t3 = v | std::views::take(3);
auto d3 = v | std::views::drop(7);
std::cout << "take(3) : ";
for (int x : t3) std::cout << x << ' ';
std::cout << '\n';
std::cout << "drop(7) : ";
for (int x : d3) std::cout << x << ' ';
std::cout << '\n';
// 5) views::reverse
std::cout << "reverse : ";
for (int x : v | std::views::reverse) std::cout << x << ' ';
std::cout << '\n';
// 6) views::iota — range bilangan
std::cout << "iota(1,6) : ";
for (int x : std::views::iota(1, 6)) std::cout << x << ' ';
std::cout << '\n';
// 7) Lazy evaluation — take dari iota infinite
long long sum = 0;
for (int x : std::views::iota(1) | std::views::take(100)) sum += x;
std::cout << "sum 1..100 = " << sum << '\n';
// 8) ranges::sort, ranges::min, ranges::max
std::vector<int> w = {5, 2, 8, 1, 9};
std::ranges::sort(w);
std::cout << "ranges::sort : ";
for (int x : w) std::cout << x << ' ';
std::cout << "(min=" << std::ranges::min(w)
<< ", max=" << std::ranges::max(w) << ")\n";
// 9) ranges::find_if
auto it = std::ranges::find_if(v, [](int x) { return x > 5; });
if (it != v.end()) std::cout << "first > 5 = " << *it << '\n';
return 0;
}Output yang Dihasilkan:
filter genap : 2 4 6 8 10
transform x10 : 10 20 30 40 50 60 70 80 90 100
pipeline : 20 40 60
take(3) : 1 2 3
drop(7) : 8 9 10
reverse : 10 9 8 7 6 5 4 3 2 1
iota(1,6) : 1 2 3 4 5
sum 1..100 = 5050
ranges::sort : 1 2 5 8 9 (min=1, max=9)
first > 5 = 6Bedah Kode Baris-per-Baris #
v | std::views::filter(...): operator|di-overload untuk komposisi view.filtermenghasilkan view yang, saat diiterasi, meminta elemen darivdan hanya meneruskan yang memenuhi predikat. Output{2,4,6,8,10}.v | std::views::transform(...): setiap elemenvdipetakan via lambdax * 10. Output{10,20,...,100}. Tidak ada alokasi container baru.- Pipeline
v | filter | transform | take(3): tiga view dikomposisikan. Pipeline memproses elemen secara lazy — saattake(3)sudah terisi tiga elemen (20, 40, 60), iterasi berhenti. Elemen{7,8,9,10}tidak pernah diproses. std::views::take(n): menghasilkan paling banyaknelemen pertama. Bila range lebih pendek, kembalikan semua.std::views::drop(n): melewatkannelemen pertama, meneruskan sisanya. Sering dipakai untuk paging atau split train/test.std::views::reverse: view iterasi mundur. Container underlying harus mendukung bidirectional iterator.std::views::iota(1, 6): range[1, 6)— yaitu{1,2,3,4,5}. Pola umum mengganti loopfor (int i = 1; i < 6; ++i).std::views::iota(1)(satu argumen): infinite range — tidak boleh diiterasi langsung. Dikombinasikan dengantake(100), ia menghasilkan{1..100}. Inilah demonstrasi lazy evaluation: range infinite tetap aman karena view membatasi paling banyak 100 elemen.std::ranges::sort(w): algoritmasortversi ranges. Tidak perlu menulisw.begin(), w.end()— cukup lewatkan container. Sama-samaO(n log n).std::ranges::min(w)/std::ranges::max(w): mengembalikan elemen minimum/maksimum. Menghilangkan kebutuhanstd::min_element(w.begin(), w.end())lalu dereference.std::ranges::find_if(v, pred): cari elemen pertama yang memenuhi predikat. Mengembalikan iterator (bukan view).
View yang Umum Dipakai #
| View | Fungsi |
|---|---|
views::filter(pred) | Saring elemen yang memenuhi predikat |
views::transform(f) | Petakan setiap elemen via f |
views::take(n) | Ambil paling banyak n elemen pertama |
views::drop(n) | Lewati n elemen pertama |
views::reverse | Iterasi mundur |
views::iota(a, b) | Range [a, b) bertambah satu |
views::keys / views::values | Iterasi key/value dari map |
views::single(x) | Range berisi satu elemen |
views::empty<T> | Range kosong bertipe T |
Ringkasan #
- C++20 Ranges memungkinkan komposisi algoritma secara deklaratif dengan operator
|. std::views::*menghasilkan lazy view — tidak menyalin data; elemen diproses saat iterasi.std::ranges::*adalah versi algoritma STL yang menerima range langsung (ranges::sort(v)).- Pipeline
v | filter | transform | takehanya memproses elemen yang diperlukan — efisien untuk data besar. - Kompilasi dengan
-std=c++20. Beberapa adaptor lanjutan butuh GCC 13+. - View umum:
filter,transform,take,drop,reverse,iota,keys/values.