Bagikan melalui


<ranges> lihat kelas

Tampilan adalah rentang ringan yang mengacu pada elemen yang tidak dimilikinya (kecuali owning_view). Tampilan biasanya didasarkan pada rentang lain dan menyediakan cara yang berbeda untuk melihatnya, baik dengan mengubah atau memfilternya. Misalnya, std::views::filter adalah tampilan yang menggunakan kriteria yang Anda tentukan untuk memilih elemen dari rentang lain.

Ketika Anda mengakses elemen dalam tampilan, itu dilakukan "malas" sehingga pekerjaan dilakukan hanya ketika Anda mendapatkan elemen. Ini memungkinkan untuk menggabungkan, atau menyusun, tampilan tanpa penalti performa.

Misalnya, Anda dapat membuat tampilan yang hanya menyediakan elemen genap dari rentang lalu mengubahnya dengan memadainya. Pekerjaan untuk melakukan pemfilteran dan transformasi dilakukan hanya untuk elemen yang Anda akses, dan hanya saat Anda mengaksesnya.

Tampilan dapat disalin, ditetapkan, dan dihancurkan dalam waktu konstan tidak peduli berapa banyak elemen yang dikandungnya. Ini karena tampilan tidak memiliki elemen yang dirujuknya, sehingga tidak perlu membuat salinan. Inilah sebabnya mengapa Anda dapat menyusun tampilan tanpa penalti performa.

Anda biasanya membuat tampilan dengan menggunakan adaptor rentang. Adaptor rentang adalah cara yang dimaksudkan untuk membuat tampilan, lebih mudah digunakan daripada membuat instans kelas tampilan secara langsung, dan terkadang lebih efisien daripada membuat instans kelas tampilan secara langsung. Kelas tampilan diekspos secara langsung jika Anda perlu membuat jenis tampilan kustom Anda sendiri berdasarkan jenis tampilan yang ada.

Berikut adalah contoh singkat membuat tampilan kuadrat elemen yang dapat dibagi tiga dalam vektor:

// requires /std:c++20 or later
#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 << ' '; // 0 9 36 81
    }
}
0 9 36 81

Menggunakan tampilan setelah rentang yang didasarkan pada dimodifikasi dapat menyebabkan perilaku yang tidak ditentukan. Misalnya, reverse_view berdasarkan vektor tidak boleh digunakan kembali jika Anda menambahkan atau menghapus elemen dari vektor yang mendasar. Memodifikasi vektor yang mendasar membatalkan iterator kontainer end --termasuk salinan iterator yang mungkin telah dibuat tampilan.

Karena tampilan murah untuk dibuat, Anda umumnya harus membuat ulang tampilan jika Anda memodifikasi rentang yang mendasar. Contoh berikut menunjukkan cara menyimpan alur tampilan dalam variabel sehingga Anda dapat menggunakannya kembali.

// requires /std:c++20, or later
#include <iostream>
#include <ranges>
#include <vector>
#include <list>
#include <string_view>
#include <algorithm>

template<typename rangeType>
void show(std::string_view msg, rangeType r)
{
    std::cout << msg;
    std::ranges::for_each(r,
        [](auto e)
        {
            std::cout << e << ' ';
        });
    std::cout << '\n';
}

int main()
{
    std::vector v{ 1, 2, 3, 4 };
    show("v: ", v);

    // You can save a view pipeline
    auto rev3 = std::views::take(3) | std::views::reverse;

    show("v | rev3: ", v | rev3); // 3 2 1

    v.insert(v.begin(), 0); // v = 0 1 2 3 4
    show("v: ", v);

    // Because modifying the vector invalidates its iterators, rebuild the view.
    // We are reusing the view pipeline we saved earlier
    show("v | rev3(v): ", rev3(v));
}
v: 1 2 3 4
v | rev3: 3 2 1
v: 0 1 2 3 4
v | rev3(v): 2 1 0

Kelas tampilan berikut didefinisikan dalam std::ranges namespace layanan.

Tampilkan Deskripsi
basic_istream_viewC++20 Tampilan elemen berturut-turut dari aliran input. Spesialisasi meliputi istream_view dan wistream_view.
common_viewC++20 Mengadaptasi tampilan yang memiliki jenis iterator/sentinel yang berbeda ke dalam tampilan dengan jenis iterator/sentinel yang sama.
drop_viewC++20 Dibuat dari tampilan lain, melewati elemen pertama count .
drop_while_viewC++20 Dibuat dari tampilan lain, melewati elemen terkemuka selama predikat bertahan.
elements_viewC++20 Tampilan di atas indeks yang dipilih ke dalam setiap nilai seperti tuple dalam koleksi. Misalnya, mengingat rentang std::tuple<string, int> nilai, buat tampilan yang terdiri dari semua string elemen dari setiap tuple.
empty_viewC++20 Tampilan tanpa elemen.
filter_viewC++20 Memfilter elemen rentang yang tidak cocok dengan predikat.
iota_viewC++20 Tampilan yang dihasilkan yang berisi urutan nilai inkrementasi.
join_viewC++20 Menggabungkan semua elemen dari beberapa rentang ke dalam satu tampilan.
keys_viewC++20 Tampilan atas indeks pertama ke dalam setiap nilai seperti tuple dalam koleksi. Misalnya, mengingat rentang std::tuple<string, int> nilai, buat tampilan yang terdiri dari string elemen dari setiap tuple.
lazy_split_viewC++20 Memisahkan tampilan menjadi subranges berdasarkan pemisah.
owning_viewC++20 Mengambil kepemilikan elemen dari rentang lain.
ref_viewC++20 Tampilan yang mereferensikan elemen yang termasuk dalam rentang lain.
reverse_viewC++20 Menyajikan elemen rentang dalam urutan terbalik.
single_viewC++20 Tampilan yang hanya berisi satu elemen.
split_viewC++20 Memisahkan tampilan menjadi subranges berdasarkan pemisah.
subrangeC++20 Tampilan bagian dari elemen rentang, seperti yang didefinisikan oleh iterator awal dan sentinel.
take_viewC++20 Berisi jumlah elemen yang ditentukan yang diambil dari depan rentang.
take_while_viewC++20 Berisi elemen terkemuka dari rentang yang cocok dengan predikat yang diberikan.
transform_viewC++20 Tampilan urutan yang mendasar setelah fungsi transformasi diterapkan ke setiap elemen.
values_viewC++20 Tampilan di atas indeks kedua ke dalam setiap nilai seperti tuple dalam koleksi. Misalnya, mengingat rentang std::tuple<string, int> nilai, buat tampilan yang terdiri dari int elemen dari setiap tuple.

Banyak dari kelas ini memiliki adaptor rentang yang sesuai di std:views namespace layanan yang membuat instansnya. Lebih suka menggunakan adaptor untuk membuat tampilan alih-alih membuat kelas tampilan secara langsung. Adaptor rentang adalah cara yang dimaksudkan untuk membuat tampilan, lebih mudah digunakan, dan dalam beberapa kasus lebih efisien.

Melihat karakteristik kelas

Setiap topik kelas tampilan memiliki bagian Karakteristik setelah bagian sintaksis. Bagian Karakteristik memiliki entri berikut:

  • Adaptor rentang: Tautan ke adaptor rentang yang membuat tampilan. Anda biasanya menggunakan adaptor rentang untuk membuat tampilan daripada membuat kelas tampilan secara langsung, sehingga tercantum di sini untuk kenyamanan.

  • Rentang yang mendasar: Tampilan memiliki persyaratan iterator yang berbeda untuk jenis rentang yang mendasar yang dapat mereka gunakan. Lihat hierarki iterator rentang untuk informasi selengkapnya tentang jenis iterator.

  • Lihat kategori iterator: Kategori iterator tampilan. Saat tampilan mengadaptasi rentang, jenis iterator untuk tampilan biasanya sama dengan jenis iterator dari rentang yang mendasar. Namun, mungkin berbeda untuk beberapa tampilan. Misalnya, reverse_view memiliki bidirectional_iterator, bahkan jika rentang yang mendasar memiliki random_access_iterator.

  • Jenis elemen: Jenis elemen yang dikembalikan iterator tampilan.

  • Ukuran: Apakah tampilan dapat mengembalikan jumlah elemen yang dirujuknya. Tidak semua tampilan bisa.

  • Rentang umum: Menentukan apakah tampilan adalah common_range, yang berarti bahwa jenis iterator dan sentinel mulai sama. Rentang umum berguna untuk kode pra-rentang yang berfungsi dengan pasangan iterator. Contohnya adalah konstruktor pasangan iterator untuk kontainer urutan, seperti vector(ranges::begin(x), ranges::end(x)).

  • Rentang yang dipinjam: Menentukan apakah tampilan adalah rentang yang dipinjam. borrowed_range<T> berarti Anda dapat menggunakan iterator untuk T setelah T dihancurkan.

    Tidak ada kontainer standar yang merupakan rentang yang dipinjam, karena menghancurkan kontainer membebaskan elemen dan membatalkan iterator apa pun. Dalam hal ini, kami mengatakan bahwa iterator dibiarkan "menjuntai" setelah kehancuran.

    Misalnya, std::ranges::find() biasanya mengembalikan iterator ke elemen yang ditemukan dalam argumen rentang. Jika argumen rentang adalah kontainer sementara (rvalue), itu adalah kesalahan untuk menyimpan iterator yang dikembalikan dan menggunakannya nanti karena "menggantung."

    Algoritma rentang yang mengembalikan iterator (atau subrang) melakukannya hanya ketika argumennya lvalues (non-sementara) atau rentang yang dipinjam. Jika tidak, mereka mengembalikan std::dangling objek, yang memberikan petunjuk dalam pesan kesalahan tentang apa yang salah jika Anda mencoba menggunakannya seperti iterator.

  • Apakah const iterable: Menunjukkan apakah Anda dapat melakukan iterasi melalui const instans tampilan. Tidak semua const tampilan dapat diulang. Jika tampilan tidak const dapat diulang, Anda tidak dapat melakukan iterasi dengan for (const auto& element : as_const(theView)) atau meneruskannya ke fungsi yang mengambil const referensi ke tampilan lalu mencoba melakukan iterasi di atasnya.

Hierarki iterator rentang

Di bagian Karakteristik dari setiap topik kelas tampilan, kategori iterator dalam kategori Rentang dasar dan Tampilan iterator mengacu pada jenis iterator yang didukung rentang/tampilan. Ada enam kategori iterator Rentang, yang diidentifikasi oleh konsep C++20. Hierarki perulangan rentang, dalam meningkatkan urutan kemampuan, adalah:

Konsep iterator rentang Deskripsi
output_range Hanya tulis, hanya bergerak maju; single-pass.
input_range Baca-saja, hanya bergerak maju; single-pass.
forward_range Hanya bergerak maju; multi-pass.
bidirectional_range Dapat bergerak maju dan mundur; multi-pass.
random_access_range Dapat mengakses koleksi dengan indeks; multi-pass.
contiguous_range Dapat mengakses koleksi dengan indeks, dan elemen disimpan secara berdampingan dalam memori.

Secara umum, iterator memiliki kemampuan iterator yang mendahuluinya dalam tabel. Misalnya, bidirectional_range memiliki kemampuan forward_range, tetapi tidak sebaliknya. Kecuali input_range, yang tidak memiliki kemampuan output_range karena Anda tidak dapat menulis ke input_range.

Pernyataan "memerlukan input_range atau lebih tinggi" berarti bahwa tampilan dapat digunakan dengan input_range, , forward_range, bidirectional_range, random_access_rangeatau contiguous_range iterator, karena semuanya mampu seperti input_range.

Hierarki iterator rentang terkait langsung dengan hierarki iterator. Untuk informasi selengkapnya, lihat Konsep iterator.

Baca juga

<ranges>
Adaptor rentang