<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_of
copy_if
, none_of
any_of
, , find
, find_if
, find_if_not
, count
, count_if
, , for_each
, , for_each_n
, , equal
dan 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.
Fungsi | Deskripsi |
---|---|
begin C++20 |
Dapatkan iterator ke elemen pertama dalam rentang. |
cbegin C++20 |
Dapatkan iterator const ke elemen pertama dalam rentang. |
cend C++20 |
Dapatkan sentinel di akhir const rentang -qualified. |
cdata C++20 |
const Dapatkan penunjuk ke elemen pertama dalam rentang yang berdampingan. |
crbegin C++20 |
Dapatkan iterator terbalik const ke awal rentang. |
crend C++20 |
Dapatkan sentinel di akhir pengembalian apa crbegin() . |
data C++20 |
Dapatkan penunjuk ke elemen pertama dalam rentang yang berdampingan. |
empty C++20 |
Tentukan apakah rentang kosong. |
end C++20 |
Dapatkan sentinel di akhir rentang. |
rbegin C++20 |
Dapatkan iterator terbalik ke awal rentang. |
rend C++20 |
Dapatkan iterator terbalik ke sentinel di akhir rentang. |
size C++20 |
Dapatkan ukuran rentang sebagai nilai yang tidak ditandatangani. |
ssize C++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_t C++20 |
Tentukan apakah iterator yang dikembalikan untuk range mengacu pada rentang yang masa pakainya telah berakhir. |
borrowed_subrange_t C++20 |
Tentukan apakah iterator yang dikembalikan untuk subrange mengacu pada subrange yang masa pakainya telah berakhir. |
dangling C++20 |
Menunjukkan bahwa iterator yang range /subrange dikembalikan dari masa pakai range /subrange yang dirujuknya. |
iterator_t C++20 |
Mengembalikan jenis iterator dari jenis rentang yang ditentukan. |
range_difference_t C++20 |
Mengembalikan jenis perbedaan dari jenis iterator rentang yang ditentukan. |
range_reference_t C++20 |
Mengembalikan jenis referensi dari jenis iterator rentang yang ditentukan. |
range_rvalue_reference_t C++20 |
Mengembalikan jenis referensi rvalue untuk jenis iterator rentang yang ditentukan. Dengan kata lain, jenis referensi rvalue dari elemen rentang. |
range_size_t C++20 |
Mengembalikan jenis yang digunakan untuk melaporkan ukuran rentang yang ditentukan. |
range_value_t C++20 |
Mengembalikan jenis nilai dari jenis iterator rentang yang ditentukan. Atau dengan kata lain, jenis elemen dalam rentang. |
sentinel_t C++20 |
Mengembalikan jenis sentinel dari rentang yang ditentukan. |
Untuk informasi selengkapnya tentang templat alias ini, lihat <ranges>
templat alias.
Lihat juga
<ranges>
Fungsi
<ranges>
Konsep
Adaptor rentang
Referensi file header