Salah satu manfaat std::begindan std::endadalah mereka berfungsi sebagai titik ekstensi untuk mengimplementasikan antarmuka standar untuk kelas eksternal.
Jika Anda ingin menggunakan CustomContainerkelas dengan rentang berbasis untuk fungsi loop atau templat yang diharapkan .begin()dan .end()metode, Anda jelas harus menerapkan metode tersebut.
Jika kelas memang menyediakan metode tersebut, itu tidak masalah. Jika tidak, Anda harus memodifikasinya *.
Ini tidak selalu layak, misalnya ketika menggunakan perpustakaan eksternal, terutama yang komersial dan sumber tertutup.
Dalam situasi seperti itu, std::begindan std::endsangat berguna, karena seseorang dapat menyediakan API iterator tanpa memodifikasi kelas itu sendiri, tetapi kelebihan fungsi bebas.
Contoh: misalkan Anda ingin menerapkan count_iffungsi yang mengambil wadah alih-alih sepasang iterator. Kode tersebut mungkin terlihat seperti ini:
template<typename ContainerType, typename PredicateType>
std::size_t count_if(const ContainerType& container, PredicateType&& predicate)
{
using std::begin;
using std::end;
return std::count_if(begin(container), end(container),
std::forward<PredicateType&&>(predicate));
}
Sekarang, untuk setiap kelas yang ingin Anda gunakan dengan kebiasaan ini count_if, Anda hanya perlu menambahkan dua fungsi gratis, daripada memodifikasi kelas-kelas itu.
Sekarang, C ++ memiliki mechanisim yang disebut Argument Dependent Lookup
(ADL), yang membuat pendekatan seperti itu bahkan lebih fleksibel.
Singkatnya, ADL berarti, bahwa ketika kompiler menyelesaikan fungsi yang tidak memenuhi syarat (yaitu fungsi tanpa namespace, seperti beginbukan std::begin), ia juga akan mempertimbangkan fungsi yang dideklarasikan dalam ruang nama argumen. Sebagai contoh:
namesapce some_lib
{
// let's assume that CustomContainer stores elements sequentially,
// and has data() and size() methods, but not begin() and end() methods:
class CustomContainer
{
...
};
}
namespace some_lib
{
const Element* begin(const CustomContainer& c)
{
return c.data();
}
const Element* end(const CustomContainer& c)
{
return c.data() + c.size();
}
}
// somewhere else:
CustomContainer c;
std::size_t n = count_if(c, somePredicate);
Dalam hal ini, tidak masalah bahwa nama yang memenuhi syarat adalah some_lib::begindan some_lib::end
- karena CustomContainerada some_lib::juga, kompiler akan menggunakan kelebihan itu di count_if.
Itu juga alasan untuk memiliki using std::begin;dan using std::end;masuk count_if. Ini memungkinkan kita untuk menggunakan tanpa pengecualian begindan end, karenanya memungkinkan ADL dan
memungkinkan kompiler untuk memilih std::begindan std::endketika tidak ada alternatif lain ditemukan.
Kita bisa makan cookie dan memiliki cookie - yaitu memiliki cara untuk menyediakan implementasi kustom begin/ endsementara kompiler dapat kembali ke yang standar.
Beberapa catatan:
Untuk alasan yang sama, ada fungsi serupa lainnya: std::rbegin/ rend,
std::sizedan std::data.
Seperti jawaban lain menyebutkan, std::versi memiliki kelebihan untuk array kosong. Itu berguna, tetapi hanya kasus khusus dari apa yang saya jelaskan di atas.
Menggunakan std::begindan berteman adalah ide yang bagus ketika menulis kode templat, karena ini membuat templat-templat tersebut lebih umum. Untuk non-templat Anda mungkin juga menggunakan metode, jika berlaku.
PS Saya tahu bahwa postingan ini sudah hampir 7 tahun. Saya menemukan itu karena saya ingin menjawab pertanyaan yang ditandai sebagai duplikat dan menemukan bahwa tidak ada jawaban di sini yang menyebutkan ADL.