Apa tujuan dari C ++ 20 std :: common_reference?

Jawaban:

46

common_reference keluar dari upaya saya untuk datang dengan konseptualisasi iterator STL yang mengakomodasi iterator proxy.

Dalam STL, iterator memiliki dua jenis minat khusus yang terkait: referencedan value_type. Yang pertama adalah jenis kembalinya iterator operator*, dan value_typemerupakan (non-const, non-referensi) jenis elemen dari urutan.

Algoritme umum sering kali perlu melakukan hal-hal seperti ini:

value_type tmp = *it;

... jadi kita tahu bahwa harus ada beberapa hubungan antara kedua jenis. Untuk iterator non-proxy hubungannya sederhana: referenceselalu value_type, opsional const dan referensi yang berkualitas. Upaya awal dalam mendefinisikan InputIteratorkonsep mensyaratkan bahwa ekspresi *itdapat dikonversi const value_type &, dan untuk iterator yang paling menarik sudah cukup.

Saya ingin iterator di C ++ 20 lebih kuat dari ini. Misalnya, perhatikan kebutuhan a zip_iteratoryang mengulangi dua urutan dalam langkah-kunci. Saat dereferensi a zip_iterator, Anda mendapatkan sementara pairdari kedua referencejenis iterator . Jadi, zipa vector<int>dan a vector<double>akan memiliki jenis-jenis terkait ini:

zipiterator's reference: pair<int &, double &>
zipiterator's value_type:pair<int, double>

Seperti yang Anda lihat, kedua jenis ini tidak saling terkait hanya dengan menambahkan kualifikasi dan level atas cv-. Namun membiarkan kedua jenis itu menjadi sewenang-wenang berbeda terasa salah. Jelas ada beberapa hubungan di sini. Tapi apa hubungannya, dan apa yang dapat diasumsikan oleh algoritma generik yang beroperasi pada iterator dengan aman tentang kedua jenis ini?

Jawaban dalam C ++ 20 adalah bahwa untuk setiap jenis iterator yang valid, proksi atau tidak, tipe reference &&dan value_type &berbagi referensi umum . Dengan kata lain, untuk beberapa iterator itada beberapa jenis CRyang membuat berikut ini terbentuk dengan baik:

void foo(CR) // CR is the common reference for iterator I
{}

void algo( I it, iter_value_t<I> val )
{
  foo(val); // OK, lvalue to value_type convertible to CR
  foo(*it); // OK, reference convertible to CR
}

CRadalah referensi umum. Semua algoritma dapat mengandalkan fakta bahwa jenis ini ada, dan dapat digunakan std::common_referenceuntuk menghitungnya.

Jadi, itulah peran yang common_referenceberperan dalam STL di C ++ 20. Secara umum, kecuali jika Anda menulis algoritma generik atau iterator proxy, Anda dapat mengabaikannya dengan aman. Itu ada di bawah penutup memastikan bahwa iterator Anda memenuhi kewajiban kontrak mereka.


EDIT: OP juga meminta contoh. Ini adalah sedikit dibikin, tapi bayangkan itu C ++ 20 dan Anda diberi berbagai random-access rjenis Rtentang yang Anda tidak tahu, dan Anda ingin sortjangkauan.

Lebih jauh bayangkan bahwa untuk beberapa alasan, Anda ingin menggunakan fungsi perbandingan monomorfik std::less<T>. (Mungkin Anda telah mengetik-menghapus rentang, dan Anda juga perlu mengetik-menghapus fungsi perbandingan dan meneruskannya melalui virtual? Sekali lagi, peregangan.) Apa yang harus Tdi dalam std::less<T>? Untuk itu Anda akan menggunakan common_reference, atau helper iter_common_reference_tyang diimplementasikan dalam hal itu.

using CR = std::iter_common_reference_t<std::ranges::iterator_t<R>>;
std::ranges::sort(r, std::less<CR>{});

Itu dijamin berfungsi, meskipun rentang rmemiliki iterator proxy.

Eric Niebler
sumber
2
Mungkin saya padat, tetapi bisakah Anda menjelaskan referensi umum apa yang ada dalam contoh zip-pair?
happydave
4
Idealnya, pair<T&,U&>dan pair<T,U>&akan memiliki referensi umum, dan itu akan menjadi sederhana pair<T&,U&>. Namun, untuk std::pair, tidak ada konversi dari pair<T,U>&ke pair<T&,U&>meskipun konversi tersebut pada prinsipnya masuk akal. (Ini, kebetulan, itulah sebabnya kami tidak memiliki zippandangan dalam C ++ 20.)
Eric Niebler
4
@EricNiebler: " Ini, kebetulan, adalah mengapa kami tidak memiliki tampilan zip di C ++ 20. " Apakah ada beberapa alasan mengapa zip iterator harus digunakan pair, alih-alih jenis yang dapat secara khusus dirancang untuk tujuannya , dengan konversi implisit yang sesuai sesuai kebutuhan?
Nicol Bolas
5
@Nicol Bolas Tidak perlu digunakan std::pair; jenis pasangan yang cocok dengan konversi yang tepat akan dilakukan, dan range-v3 mendefinisikan jenis pasangan seperti itu. Di Komite, LEWG tidak menyukai gagasan untuk menambahkan ke Perpustakaan Standar jenis yang hampir tetapi tidak cukup std::pair, baik itu normatif atau tidak, tanpa terlebih dahulu melakukan uji tuntas tentang pro dan kontra dari hanya membuat std::pairpekerjaan.
Eric Niebler
3
tuple, pair, tomato, to- MAH- to. pairmemiliki fitur bagus yang dapat Anda akses elemen dengan .firstdan .second. Binding terstruktur membantu dengan beberapa kecanggungan bekerja dengan tuples, tetapi tidak semua.
Eric Niebler