Manakah dari berikut ini yang menurut Anda lebih mudah dibaca? Lingkaran tulisan tangan:
for (std::vector<Foo>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
bar.process(*it);
}
Atau doa algoritma:
#include <algorithm>
#include <functional>
std::for_each(vec.begin(), vec.end(),
std::bind1st(std::mem_fun_ref(&Bar::process), bar));
Saya bertanya-tanya apakah std::for_each
benar-benar layak, mengingat contoh sederhana seperti itu sudah membutuhkan begitu banyak kode.
Apa pendapat Anda tentang hal ini?
c++
algorithms
fredoverflow
sumber
sumber
map(bar.process, vec)
meskipun peta untuk efek samping tidak disarankan dan daftar pemahaman / ekspresi generator direkomendasikan pada peta).BOOST_FOREACH
...Jawaban:
Ada alasan mengapa lambda diperkenalkan, dan itu karena bahkan Komite Standar mengakui bahwa bentuk kedua menyebalkan. Gunakan formulir pertama, sampai Anda mendapatkan dukungan C ++ 0x dan lambda.
sumber
Selalu gunakan varian yang paling menggambarkan apa yang ingin Anda lakukan. Itu adalah
Sekarang, mari kita periksa contoh-contohnya:
Kami punya di
for_each
sana juga - Yippeh . Kami memiliki[begin; end)
rentang yang ingin kami operasikan.Pada prinsipnya, algoritma itu jauh lebih eksplisit dan dengan demikian lebih disukai daripada implementasi tulisan tangan. Tapi kemudian ... Binder? Memfun? Pada dasarnya C ++ interna tentang cara mendapatkan fungsi anggota? Untuk tugas saya, saya tidak peduli tentang mereka! Saya juga tidak ingin menderita sintaksis verbose yang menyeramkan ini.
Sekarang kemungkinan lainnya:
Memang, ini adalah pola umum untuk dikenali, tapi ... membuat iterator, looping, incrementing, dereferencing. Ini juga semua hal yang tidak saya pedulikan untuk menyelesaikan tugas saya.
Diakui, terlihat waay lebih baik dari solusi pertama (setidaknya, loop tubuh yang fleksibel dan cukup eksplisit), tapi masih, itu tidak benar-benar yang besar. Kami akan menggunakan ini jika kami tidak memiliki kemungkinan yang lebih baik, tapi mungkin kami ...
Cara yang lebih baik?
Sekarang kembali ke
for_each
. Bukankah bagus untuk mengatakanfor_each
dan fleksibel dalam operasi yang harus dilakukan juga? Untungnya, sejak C ++ 0x lambdas, kamiSekarang kami telah menemukan solusi abstrak dan generik untuk banyak situasi terkait, perlu dicatat bahwa dalam kasus khusus ini, ada favorit # 1 mutlak :
Benar-benar tidak bisa lebih jelas dari itu. Untungnya, C ++ 0x mendapatkan ini sintaks mirip built-in !
sumber
for (const Foo& x : vec) bar.process(x);
, atau menggunakanconst auto&
jika Anda suka.const auto&
adalah mungkin? Tidak tahu itu - info hebat!Karena ini sangat tidak dapat dibaca?
sumber
int
dengan dengansize_t
berbahaya. Juga, pengindeksan tidak berfungsi pada setiap wadah, misalnyastd::set
.secara umum, bentuk pertama dapat dibaca oleh hampir semua orang yang tahu apa itu for-loop, tidak peduli apa latar belakang yang mereka miliki.
juga secara umum, yang kedua tidak bisa dibaca sama sekali: cukup mudah mencari tahu apa yang for_each lakukan, tetapi jika Anda belum pernah melihat
std::bind1st(std::mem_fun_ref
saya bisa membayangkan itu sulit untuk dimengerti.sumber
Sebenarnya, bahkan dengan C ++ 0x, saya tidak yakin
for_each
akan mendapatkan banyak cinta.Jauh lebih mudah dibaca.
Satu hal yang saya tidak suka tentang algoritma (dalam C + +) adalah mereka beralasan di iterator, membuat pernyataan yang sangat verbose.
sumber
Jika Anda telah menulis bilah sebagai functor maka itu akan jauh lebih sederhana:
Di sini kodenya cukup mudah dibaca.
sumber
Saya lebih suka yang terakhir karena rapi dan bersih. Ini sebenarnya bagian dari banyak bahasa lain tetapi di C ++, itu bagian dari perpustakaan. Itu tidak terlalu penting.
sumber
Sekarang masalah ini sebenarnya tidak spesifik untuk C ++, saya akan mengklaim.
Masalahnya, melewatkan beberapa functor ke fungsi lain tidak dimaksudkan untuk mengganti loop .
Seharusnya menyederhanakan pola tertentu, yang menjadi sangat alami dengan pemrograman fungsional, seperti pengunjung dan pengamat , hanya untuk menyebutkan dua, yang langsung muncul di pikiran saya.
Dalam bahasa yang tidak memiliki fungsi urutan pertama (Java mungkin adalah contoh terbaik), pendekatan seperti itu selalu membutuhkan penerapan beberapa antarmuka yang diberikan, yang cukup verba dan berlebihan.
Penggunaan umum yang sering saya lihat dalam bahasa lain adalah:
Keuntungan dari ini adalah, bahwa Anda tidak perlu tahu bagaimana
someCollection
sebenarnya diimplementasikan atausomeUnaryFunctor
tidak. Yang perlu Anda ketahui adalah, bahwaforEach
metodenya akan mengulangi semua elemen koleksi, meneruskannya ke fungsi yang diberikan.Secara pribadi, jika Anda berada dalam posisi, untuk memiliki semua informasi tentang struktur data yang ingin Anda iterate dan semua informasi tentang apa yang ingin Anda lakukan dalam setiap langkah iterasi, maka pendekatan fungsional adalah hal-hal yang rumit, terutama dalam bahasa, di mana ini tampaknya cukup membosankan.
Juga, Anda harus ingat, bahwa pendekatan fungsional lebih lambat, karena Anda memiliki banyak panggilan, yang datang dengan biaya tertentu, yang tidak Anda miliki dalam perulangan for.
sumber
std::for_each(vec.begin(), vec.end(), std::bind1st(std::mem_fun_ref(&Bar::process), bar));
Dan itu lebih lambat saat runtime atau waktu kompilasi (jika Anda beruntung). Saya tidak melihat mengapa mengganti struktur kontrol aliran dengan pemanggilan fungsi membuat kode lebih baik. Tentang segala alternatif yang disajikan di sini lebih mudah dibaca.Saya pikir masalahnya di sini adalah bahwa
for_each
itu bukan algoritma, itu hanya cara yang berbeda (dan biasanya lebih rendah) untuk menulis loop tulisan tangan. dari perspektif ini seharusnya algoritma standar yang paling sedikit digunakan, dan ya Anda mungkin juga menggunakan for loop. namun saran dalam judul masih berlaku karena ada beberapa algoritma standar yang disesuaikan dengan penggunaan yang lebih spesifik.Di mana ada algoritma yang lebih ketat melakukan apa yang Anda inginkan maka ya Anda harus memilih algoritma melalui loop tulisan tangan. contoh yang jelas di sini adalah pengurutan dengan
sort
ataustable_sort
atau pencarian denganlower_bound
,upper_bound
atauequal_range
, tetapi kebanyakan dari mereka memiliki beberapa situasi di mana mereka lebih disukai untuk digunakan daripada loop kode tangan.sumber
Untuk cuplikan kode kecil ini, keduanya sama-sama dapat dibaca oleh saya. Secara umum, saya menemukan loop manual rawan kesalahan dan lebih suka menggunakan algoritma, tetapi itu benar-benar tergantung pada situasi yang konkret.
sumber