Bagikan melalui


<ranges>

Pada tingkat tinggi, rentang adalah sesuatu yang dapat Anda iterasi. Rentang diwakili oleh iterator yang menandai awal rentang dan sentinel yang menandai akhir rentang. Sentinel mungkin jenis yang sama dengan iterator mulai, atau mungkin berbeda. Kontainer, seperti vector dan list, di Pustaka Standar C++ adalah rentang. Rentang mengabstraksi iterator dengan cara yang menyederhanakan dan memperkuat kemampuan Anda untuk menggunakan Pustaka Templat Standar (STL).

Algoritma STL biasanya membawa iterator yang menunjuk ke bagian koleksi yang harus mereka operasikan. Misalnya, pertimbangkan cara Anda mengurutkan vector dengan menggunakan std::sort(). Anda melewati dua iterator yang menandai awal dan akhir vector. Itu memberikan fleksibilitas, tetapi meneruskan iterator ke algoritma adalah pekerjaan ekstra karena Anda mungkin hanya ingin mengurutkan semuanya.

Dengan rentang, Anda dapat memanggil std::ranges::sort(myVector);, yang diperlakukan seolah-olah Anda memanggil std::sort(myVector.begin(), myVector.end());. Dalam pustaka rentang, algoritma mengambil rentang sebagai parameter (meskipun mereka juga dapat mengambil iterator, jika Anda mau). Mereka dapat beroperasi langsung pada koleksi. Contoh algoritma rentang yang tersedia di <algorithm> meliputi , , copy_n, , all_ofcopy_if, none_ofany_of, , find, find_if, find_if_not, count, count_if, , for_each, , for_each_n, , equaldan mismatch.copy

Tetapi mungkin manfaat rentang yang paling penting adalah Anda dapat menyusun algoritma STL yang beroperasi pada rentang dalam gaya yang mengingatkan pada pemrograman fungsional.

Contoh rentang

Sebelum rentang, jika Anda ingin mengubah elemen koleksi yang memenuhi kriteria tertentu, Anda perlu memperkenalkan langkah perantara untuk menahan hasil antar operasi. Misalnya, jika Anda ingin membangun vektor kuadrat dari elemen di vektor lain yang dapat dibagi tiga, Anda dapat menulis sesuatu seperti:

std::vector<int> input = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::vector<int> intermediate, output;

std::copy_if(input.begin(), input.end(), std::back_inserter(intermediate), [](const int i) { return i%3 == 0; });
std::transform(intermediate.begin(), intermediate.end(), std::back_inserter(output), [](const int i) {return i*i; });

Dengan rentang, Anda dapat mencapai hal yang sama tanpa memerlukan intermediate vektor:

// requires /std:c++20
std::vector<int> input = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

auto output = input
    | std::views::filter([](const int n) {return n % 3 == 0; })
    | std::views::transform([](const int n) {return n * n; });

Selain lebih mudah dibaca, kode ini menghindari alokasi memori yang diperlukan untuk intermediate vektor dan isinya. Ini juga memungkinkan Anda untuk menyusun dua operasi.

Dalam kode sebelumnya, setiap elemen yang dapat dibagi tiga dikombinasikan dengan operasi untuk mengkuadratkan elemen tersebut. Simbol pipa (|) menautkan operasi bersama-sama dan dibaca dari kiri ke kanan.

Hasilnya, output, adalah jenis rentang yang disebut tampilan.

Tampilan

Tampilan adalah rentang yang ringan. Lihat operasi--seperti konstruksi default, memindahkan konstruksi/penugasan, konstruksi/penugasan salinan (jika ada), penghancuran, dimulai, dan berakhir--semua terjadi dalam waktu konstan terlepas dari jumlah elemen dalam tampilan.

Tampilan dibuat oleh adaptor rentang, yang dibahas di bagian berikut. Untuk informasi selengkapnya tentang kelas yang mengimplementasikan berbagai tampilan, lihat Melihat kelas.

Bagaimana elemen dalam tampilan muncul tergantung pada adaptor rentang yang Anda gunakan untuk membuat tampilan. Dalam contoh sebelumnya, adaptor rentang mengambil rentang dan mengembalikan tampilan elemen yang dapat dibagi tiga. Rentang yang mendasar tidak berubah.

Tampilan dapat dikompositasikan, yang kuat. Dalam contoh sebelumnya, tampilan elemen vektor yang dapat dibagi tiga dikombinasikan dengan tampilan yang mengkuadratkan elemen-elemen tersebut.

Elemen tampilan dievaluasi dengan malas. Artinya, transformasi yang Anda terapkan ke setiap elemen dalam tampilan tidak dievaluasi sampai Anda meminta elemen . Misalnya, jika Anda menjalankan kode berikut dalam debugger dan menempatkan titik henti pada baris auto divisible_by_three = ... dan auto square = ..., Anda akan melihat bahwa Anda mencapai titik henti divisible_by_three lambda karena setiap elemen diuji input untuk pembagibilitas sebanyak tiga. Titik square henti lambda akan dipukul karena elemen yang dapat dibagi tiga dikuadratkan.

// requires /std:c++20
#include <ranges>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> input =  { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    auto divisible_by_three = [](const int n) {return n % 3 == 0; };
    auto square = [](const int n) {return n * n; };

    auto x = input | std::views::filter(divisible_by_three)
                   | std::views::transform(square);

    for (int i : x)
    {
        std::cout << i << '\n';
    }
    return 0;
}

Untuk informasi selengkapnya tentang tampilan, lihat <ranges> melihat kelas.

Adaptor rentang

Adaptor rentang mengambil rentang dan menghasilkan tampilan. Adaptor rentang menghasilkan tampilan yang dievaluasi dengan malas. Artinya, Anda tidak dikenakan biaya mengubah setiap elemen dalam rentang untuk menghasilkan tampilan. Anda hanya membayar biaya untuk memproses elemen dalam tampilan saat Anda mengakses elemen tersebut.

Dalam contoh sebelumnya, filter adaptor rentang membuat tampilan bernama input yang berisi elemen yang dapat dibagi tiga. transform Adaptor rentang mengambil tampilan elemen yang dapat dibagi tiga dan membuat tampilan elemen tersebut kuadrat.

Adaptor rentang dapat dirantai bersama -sama (terdiri), yang merupakan inti dari kekuatan dan fleksibilitas rentang. Menyusun adaptor rentang memungkinkan Anda mengatasi masalah bahwa algoritma STL sebelumnya tidak mudah dikomposisikan.

Untuk informasi selengkapnya tentang membuat tampilan, lihat Adaptor rentang.

Algoritma rentang

Beberapa algoritma rentang mengambil argumen rentang. Contohnya std::ranges::sort(myVector);.

Algoritma rentang hampir identik dengan algoritma pasangan iterator yang sesuai di std namespace layanan. Perbedaannya adalah bahwa mereka memiliki batasan yang diberlakukan konsep, dan mereka menerima argumen rentang atau lebih pasangan argumen iterator-sentinel. Mereka dapat bekerja langsung pada kontainer dan dapat dengan mudah dirangkai bersama-sama.

Fungsi <ranges>

Fungsi berikut digunakan untuk membuat iterator dan sentinel untuk rentang, dan untuk mendapatkan ukuran rentang.

Function Deskripsi
beginC++20 Dapatkan iterator ke elemen pertama dalam rentang.
cbeginC++20 Dapatkan iterator const ke elemen pertama dalam rentang.
cendC++20 Dapatkan sentinel di akhir constrentang -qualified.
cdataC++20 const Dapatkan penunjuk ke elemen pertama dalam rentang yang berdampingan.
crbeginC++20 Dapatkan iterator terbalik const ke awal rentang.
crendC++20 Dapatkan sentinel di akhir pengembalian apa crbegin() .
dataC++20 Dapatkan penunjuk ke elemen pertama dalam rentang yang berdampingan.
emptyC++20 Tentukan apakah rentang kosong.
endC++20 Dapatkan sentinel di akhir rentang.
rbeginC++20 Dapatkan iterator terbalik ke awal rentang.
rendC++20 Dapatkan iterator terbalik ke sentinel di akhir rentang.
sizeC++20 Dapatkan ukuran rentang sebagai nilai yang tidak ditandatangani.
ssizeC++20 Dapatkan ukuran rentang sebagai nilai yang ditandatangani.

Untuk informasi selengkapnya, lihat <ranges> fungsi.

Konsep rentang

Cara Anda melakukan iterasi atas elemen rentang tergantung pada jenis iterator yang mendasarnya. Rentang menggunakan konsep C++ yang menentukan iterator mana yang mereka dukung.

Dalam C++20, untuk mengatakan bahwa konsep X menyempurnakan konsep Y berarti bahwa semua yang memenuhi konsep Y juga memenuhi konsep X. Misalnya: mobil, bus, dan truk semuanya menyempurnakan kendaraan.

Beberapa konsep rentang mencerminkan hierarki kategori iterator. Tabel berikut mencantumkan konsep rentang, bersama dengan jenis kontainer yang dapat diterapkan.

Konsep rentang Deskripsi Kontainer yang didukung
std::ranges::output_range Dapat melakukan iterasi ke depan.
std::ranges::input_range Dapat melakukan iterasi dari awal hingga akhir setidaknya sekali. std::forward_list
std::unordered_map
std::unordered_multimap
std::unordered_set
std::unordered_multiset
basic_istream_view
std::ranges::forward_range Dapat melakukan iterasi dari awal hingga akhir lebih dari sekali. std::forward_list
std::unordered_map
std::unordered_multimap
std::unordered_set
std::unordered_multiset
std::ranges::bidirectional_range Dapat melakukan iterasi ke depan dan mundur lebih dari sekali. std::list
std::map
std::multimap
std::multiset
std::set
std::ranges::random_access_range Dapat mengakses elemen arbitrer (dalam waktu konstan) dengan menggunakan [] operator. std::deque
std::ranges::contiguous_range Elemen disimpan dalam memori secara berturut-turut. std::array
std::string
std::vector

Lihat <ranges> konsep untuk informasi selengkapnya tentang konsep ini.

<ranges> templat alias

Templat alias berikut menentukan jenis iterator dan sentinel untuk rentang:

Templat alias Deskripsi
borrowed_iterator_tC++20 Tentukan apakah iterator yang dikembalikan untuk range mengacu pada rentang yang masa pakainya telah berakhir.
borrowed_subrange_tC++20 Tentukan apakah iterator yang dikembalikan untuk subrange mengacu pada subrange yang masa pakainya telah berakhir.
danglingC++20 Menunjukkan bahwa iterator yang range/subrange dikembalikan dari masa pakai range/subrange yang dirujuknya.
iterator_tC++20 Mengembalikan jenis iterator dari jenis rentang yang ditentukan.
range_difference_tC++20 Mengembalikan jenis perbedaan dari jenis iterator rentang yang ditentukan.
range_reference_tC++20 Mengembalikan jenis referensi dari jenis iterator rentang yang ditentukan.
range_rvalue_reference_tC++20 Mengembalikan jenis referensi rvalue untuk jenis iterator rentang yang ditentukan. Dengan kata lain, jenis referensi rvalue dari elemen rentang.
range_size_tC++20 Mengembalikan jenis yang digunakan untuk melaporkan ukuran rentang yang ditentukan.
range_value_tC++20 Mengembalikan jenis nilai dari jenis iterator rentang yang ditentukan. Atau dengan kata lain, jenis elemen dalam rentang.
sentinel_tC++20 Mengembalikan jenis sentinel dari rentang yang ditentukan.

Untuk informasi selengkapnya tentang templat alias ini, lihat <ranges> templat alias.

Baca juga

<ranges> Fungsi
<ranges> Konsep
Adaptor rentang
Referensi file header