Mengapa std::set tidak memiliki "berisi" fungsi anggota?
I'm berat menggunakan std::set<int>
dan sering aku hanya perlu memeriksa jika set tersebut berisi nomor atau tidak.
I'd menemukannya alami menulis:
if (myset.contains(number))
...
Tetapi karena kurangnya berisi
anggota, saya perlu menulis rumit:
if (myset.find(number) != myset.end())
..
atau tidak jelas:
if (myset.count(element) > 0)
..
Apakah ada alasan untuk keputusan desain ini ?
96
8
Saya pikir itu mungkin karena mereka mencoba untuk membuat
std::set
danstd::multiset
semirip mungkin. (Dan jelasmenghitung
telah sempurna makna yang masuk akal untukstd::multiset
.)Secara pribadi saya pikir ini adalah sebuah kesalahan.
Itu doesn't terlihat begitu buruk jika anda berpura-pura bahwa
menghitung
hanya kesalahan ejaanberisi
dan menulis tes seperti:It's masih malu sekalipun.
Untuk dapat menulis
jika (s.berisi())
,mengandung()
telah kembalibool
(atau jenis convertible untukbool
, yang adalah cerita lain), sepertibinary_search
tidak.The alasan mendasar di balik keputusan desain tidak untuk melakukannya dengan cara ini adalah yang
berisi()
yang kembalibool
akan kehilangan informasi berharga tentang di mana elemen dalam koleksi ini.find()
mempertahankan dan mengembalikan informasi tersebut dalam bentuk sebuah iterator, karena itu adalah pilihan yang lebih baik untuk generik perpustakaan seperti STL. Ini selalu menjadi prinsip untuk Alex Stepanov, karena ia telah sering dijelaskan (misalnya, [di sini][1]).Untuk menghitung
()
pendekatan secara umum, meskipun itu's sering oke pemecahan masalah, masalah dengan itu adalah bahwa ini tidak bekerja lebih dariberisi()
akan dilakukan.Itu bukan untuk mengatakan bahwa
bool berisi()
isn't yang sangat bagus untuk dimiliki atau bahkan diperlukan. Beberapa saat yang lalu kami memiliki diskusi panjang tentang hal ini masalah yang sama di ISO Standar C++ - masa Depan Proposal kelompok.Kekurangan itu karena tidak ada yang ditambahkan. Tak ada yang menambahkan ini karena wadah dari STL bahwa
std
perpustakaan yang tergabung di mana dirancang untuk menjadi minimal di antarmuka. (Perhatikan bahwastd::string
tidak datang dari STL dalam cara yang sama).Jika anda don't pikiran beberapa sintaks aneh, anda dapat palsu itu:
gunakan:
Pada dasarnya, anda dapat menulis metode ekstensi untuk sebagian besar C++
std
jenis menggunakan teknik ini.Hal ini membuat banyak lebih masuk akal untuk hanya melakukan ini:
tapi saya geli dengan metode penyuluhan metode.
Benar-benar menyedihkan adalah bahwa tulisan yang efisien
berisi
bisa menjadi lebih cepat padamultimap
ataumultiset
, karena mereka hanya harus menemukan satu elemen, sementarahitung
untuk menemukan masing-masing dari mereka dan menghitung mereka.Suatu multiset yang mengandung 1 miliar salinan dari 7 (anda tahu, dalam kasus anda kehabisan) dapat benar-benar lambat
.count(7)
, tapi bisa sangat cepatberisi(7)
.Dengan penjelasan di atas metode penyuluhan, kita bisa membuatnya lebih cepat untuk kasus ini dengan menggunakan
lower_bound
, membandingkanend
, dan kemudian membandingkan elemen. Melakukan hal itu untuk unordered meow serta memerintahkan meow akan memerlukan mewah SFINAE atau wadah tertentu overload namun.Anda melihat ke dalam kasus tertentu dan tidak melihat gambaran yang lebih besar. Seperti yang dinyatakan dalam dokumentasi
std::set
memenuhi kebutuhan AssociativeContainer konsep. Untuk itu konsep ini tidak masuk akal untuk memilikiberisi
metode, seperti yang cukup banyak berguna untukstd::multiset
danstd::multimap
, tapimenghitung
bekerja dengan baik untuk mereka semua. Meskipun metodeberisi
bisa ditambahkan sebagai alias untukmenghitung
untukstd::set
,std::map
dan mereka hash versi (sepertipanjang
untuk ukuran()
dalamstd::string
), tapi tampak seperti perpustakaan pencipta tidak melihat kebutuhan nyata untuk itu.Meskipun aku don't tahu mengapa
std::set
tidakberisi
tapicount
yang hanya pernah kembali0
atau1
, anda dapat menulis kerangkaberisi
penolong fungsi seperti ini:Dan menggunakannya seperti ini:
Alasan yang benar untuk
mengatur
adalah sebuah misteri bagi saya, tapi salah satu penjelasan yang mungkin untuk ini desain yang sama dipeta
bisa untuk mencegah orang-orang untuk menulis kode yang tidak efisien oleh kecelakaan:Yang akan menghasilkan dua
peta
lookup.Sebaliknya, anda dipaksa untuk mendapatkan sebuah iterator. Ini memberi anda sebuah mental petunjuk bahwa anda harus menggunakan kembali iterator:
yang hanya mengkonsumsi satu
peta
lookup.Ketika kita menyadari bahwa
set
danpeta
yang dibuat dari daging yang sama, kita dapat menerapkan prinsip ini juga untukmengatur
. Artinya, jika kita ingin bertindak pada item dalamset
hanya jika hadir diset
, desain ini dapat mencegah kita dari menulis kode seperti ini:Tentu saja semua ini adalah spekulasi belaka.
Bagaimana binary_search ?
Alasan lain adalah bahwa hal itu akan memberikan programmer kesan palsu bahwa std::set adalah satu set dalam matematika teori akal. Jika mereka melaksanakan itu, maka banyak pertanyaan lain akan mengikuti: jika std::set telah mengandung() untuk nilai, mengapa doesn't memilikinya untuk satu set? Di mana uni(), persimpangan() dan lain mengatur operasi dan predikat?
Jawabannya adalah, tentu saja, bahwa beberapa set operasi yang sudah diimplementasikan sebagai fungsi in (std::set_union() dll.) dan lain-lain adalah sebagai mudah dilaksanakan karena mengandung(). Fungsi dan fungsi benda-benda bekerja lebih baik dengan matematika abstraksi dari objek anggota, dan mereka tidak terbatas untuk tertentu jenis wadah.
Jika salah satu kebutuhan untuk melaksanakan penuh matematika-set fungsi, dia tidak hanya pilihan yang mendasari wadah, tetapi juga ia memiliki pilihan rincian pelaksanaan, misalnya, akan theory_union() fungsi bekerja dengan benda berubah, lebih cocok untuk pemrograman fungsional, atau akan memodifikasi operan dan menyimpan memori? Itu akan diimplementasikan sebagai fungsi objek dari awal atau'a menjadi lebih baik dengan menerapkan C-fungsi, dan menggunakan std::fungsi<> jika diperlukan?
Seperti sekarang, std::set adalah hanya sebuah wadah, cocok untuk pelaksanaan diatur dalam matematika akal, tetapi hal ini hampir seperti jauh dari yang teoritis ditetapkan sebagai std::vektor dari yang teoritis vektor.