Ada banyak fungsi yang berguna <algorithm>
, tetapi semuanya beroperasi pada "urutan" - pasangan iterator. Misalnya, jika saya memiliki wadah dan suka menjalankannya std::accumulate
, saya perlu menulis:
std::vector<int> myContainer = ...;
int sum = std::accumulate(myContainer.begin(), myContainer.end(), 0);
Yang ingin saya lakukan adalah:
int sum = std::accumulate(myContainer, 0);
Yang sedikit lebih mudah dibaca dan lebih jelas, di mata saya.
Sekarang saya bisa melihat bahwa mungkin ada kasus di mana Anda hanya ingin beroperasi pada bagian-bagian wadah, jadi itu pasti berguna untuk memiliki opsi melewati rentang. Tapi setidaknya dalam pengalaman saya, itu adalah kasus khusus yang langka. Saya biasanya ingin beroperasi di seluruh wadah.
Sangat mudah untuk menulis fungsi pembungkus yang mengambil wadah dan panggilan begin()
dan end()
di atasnya, tetapi fungsi kenyamanan tersebut tidak termasuk dalam perpustakaan standar.
Saya ingin tahu alasan di balik pilihan desain STL ini.
sumber
boost::accumulate
Jawaban:
Ini mungkin kasus khusus yang langka dalam pengalaman Anda , tetapi dalam kenyataannya seluruh wadah adalah kasus khusus, dan kisaran sewenang - wenang adalah kasus umum.
Anda telah memperhatikan bahwa Anda dapat mengimplementasikan seluruh wadah menggunakan antarmuka saat ini, tetapi Anda tidak dapat melakukan yang sebaliknya.
Jadi, penulis perpustakaan memiliki pilihan antara mengimplementasikan dua antarmuka di muka, atau hanya mengimplementasikan satu yang masih mencakup semua kasus.
Benar, terutama karena fungsi gratis
std::begin
danstd::end
sekarang disertakan.Jadi, katakanlah perpustakaan menyediakan kenyamanan berlebih:
sekarang ini juga perlu menyediakan kelebihan yang setara dengan mengambil fungsi perbandingan, dan kami perlu menyediakan yang setara untuk setiap algoritma lainnya.
Tapi setidaknya kita membahas setiap kasus di mana kita ingin beroperasi pada wadah penuh, kan? Ya tidak cukup. Mempertimbangkan
Jika kita ingin menangani pengoperasian mundur pada wadah, kita memerlukan metode lain (atau pasangan metode) per algoritma yang ada.
Jadi, pendekatan berbasis rentang lebih umum dalam arti sederhana bahwa:
Ada alasan sah lainnya, tentu saja, yaitu karena sudah banyak pekerjaan untuk mendapatkan standar STL, dan menggelembungkannya dengan pembungkus yang nyaman sebelum digunakan secara luas tidak akan banyak menggunakan waktu komite yang terbatas. Jika Anda tertarik, Anda dapat menemukan laporan teknis Stepanov & Lee di sini
Seperti disebutkan dalam komentar, Boost.Range memberikan pendekatan yang lebih baru tanpa memerlukan perubahan standar.
sumber
f(c.begin(), c.end(), ...)
, dan mungkin hanya kelebihan beban yang paling umum digunakan (namun Anda menentukannya) untuk mencegah penggandaan jumlah kelebihan beban. Juga, adaptor iterator sepenuhnya ortogonal (seperti yang Anda perhatikan, mereka bekerja dengan baik di Python, yang iteratornya bekerja sangat berbeda dan tidak memiliki sebagian besar kekuatan yang Anda bicarakan).std::sort(std::range(start, stop))
.#define MAKE_RANGE(container) (container).begin(), (container).end()
</jk>Ternyata ada artikel oleh Herb Sutter tentang hal ini. Pada dasarnya, masalahnya adalah ambiguitas yang berlebihan. Diberikan sebagai berikut:
Dan menambahkan yang berikut ini:
Akan membuat sulit untuk dibedakan
4
dan1
benar.Konsep, seperti yang diusulkan tetapi pada akhirnya tidak termasuk dalam C ++ 0x, akan memecahkan itu, dan juga mungkin untuk mengelak menggunakan itu
enable_if
. Untuk beberapa algoritma, tidak ada masalah sama sekali. Tetapi mereka memutuskan untuk tidak melakukannya.Sekarang setelah membaca semua komentar dan jawaban di sini, saya pikir
range
objek akan menjadi solusi terbaik. Saya pikir saya akan melihatBoost.Range
.sumber
typename Iter
sepertinya terlalu diketik bebek untuk bahasa yang ketat. Saya lebih suka egtemplate<typename Container> void sort(typename Container::iterator, typename Container::iterator); // 1
dantemplate<template<class> Container, typename T> void sort( Container<T>&, std::function<bool(const T&)> ); // 4
lain - lain (yang mungkin akan memecahkan masalah ambiguitas)T[]::iterator
tersedia. Selain itu, iterator yang tepat tidak wajib menjadi tipe bersarang dari koleksi apa pun, itu cukup untuk didefinisikanstd::iterator_traits
.Pada dasarnya keputusan warisan. Konsep iterator dimodelkan pada pointer, tetapi kontainer tidak dimodelkan pada array. Selain itu, karena array sulit untuk dilewati (perlu parameter template non-type untuk panjang, secara umum), cukup sering fungsi hanya memiliki pointer yang tersedia.
Tapi ya, kalau dipikir-pikir keputusannya salah. Kita akan lebih baik dengan objek jangkauan yang dapat dibangun dari salah satu
begin/end
ataubegin/length
; sekarang kami memiliki beberapa_n
algoritma suffixed sebagai gantinya.sumber
Menambahkannya tidak akan memberi Anda kekuatan (Anda sudah dapat melakukan seluruh wadah dengan menelepon
.begin()
dan.end()
diri sendiri), dan itu akan menambah satu hal lagi ke perpustakaan yang harus ditentukan dengan benar, ditambahkan ke perpustakaan oleh vendor, diuji, dipelihara, dll, dll.Singkatnya, itu mungkin tidak ada karena tidak ada masalah dengan mempertahankan satu set templat tambahan hanya untuk menyelamatkan pengguna dari seluruh wadah dari mengetik satu parameter fungsi panggilan ekstra.
sumber
std::getline
, dan masih, itu ada di perpustakaan. Orang bisa mengatakan bahwa struktur kontrol yang diperluas tidak mendapatkan daya untuk saya, karena saya bisa melakukan semuanya hanya dengan menggunakanif
dangoto
. Ya, perbandingan tidak adil, saya tahu;) Saya pikir saya bisa memahami spesifikasi / implementasi / beban pemeliharaan entah bagaimana, tapi itu hanya bungkus kecil yang sedang kita bicarakan di sini, jadi ...Sekarang, http://en.wikipedia.org/wiki/C++11#Range-based_for_loop adalah alternatif yang bagus
std::for_each
. Amati, tidak ada iterator eksplisit:(Terinspirasi oleh https://stackoverflow.com/a/694534/2097284 .)
sumber
<algorithm>
, tidak semua algos aktual yang dibutuhkanbegin
danend
iterator - tetapi manfaatnya tidak dapat dilebih-lebihkan! Ketika saya pertama kali mencoba C ++ 03 di 2009ish, saya menghindar dari iterator karena lapisan perulangan, dan untungnya atau tidak, proyek saya pada saat itu mengizinkan ini. Mulai ulang pada C ++ 11 pada tahun 2014, itu adalah peningkatan yang luar biasa, bahasa C ++ selalu seharusnya, dan sekarang saya tidak bisa hidup tanpaauto &it: them
:)