का एक लाभ std::begin
और std::end
है कि वे बाहरी कक्षाओं के लिए मानक इंटरफेस को लागू करने के लिए विस्तार अंक के रूप में सेवा है।
यदि आप CustomContainer
लूप या टेम्प्लेट फ़ंक्शन के लिए श्रेणी-आधारित के साथ वर्ग का उपयोग करना चाहते हैं जो अपेक्षा करता है .begin()
और .end()
विधियां करता है, तो आपको स्पष्ट रूप से उन विधियों को लागू करना होगा।
यदि वर्ग उन तरीकों को प्रदान करता है, तो यह समस्या नहीं है। जब ऐसा नहीं होता है, तो आपको इसे संशोधित करना होगा *।
यह हमेशा संभव नहीं होता है, उदाहरण के लिए, बाहरी पुस्तकालय, निबंधात्मक वाणिज्यिक और बंद स्रोत एक का उपयोग करते समय।
ऐसी स्थितियों में, std::begin
और std::end
काम में आते हैं, क्योंकि कोई भी वर्ग को संशोधित किए बिना पुनरावृत्त एपीआई प्रदान कर सकता है, बल्कि मुफ्त कार्यों को ओवरलोड कर सकता है।
उदाहरण: मान लें कि आप ऐसे count_if
फ़ंक्शन को कार्यान्वित करना चाहते हैं जो पुनरावृत्तियों की एक जोड़ी के बजाय एक कंटेनर लेता है। ऐसा कोड इस तरह दिख सकता है:
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));
}
अब, किसी भी वर्ग के लिए जिसे आप इस रिवाज के साथ उपयोग करना चाहते हैं count_if
, आपको उन कक्षाओं को संशोधित करने के बजाय केवल दो मुफ्त फ़ंक्शंस जोड़ने होंगे।
अब, C ++ में Argument Dependent Lookup
(ADL) नामक एक मैकेनिज्म है , जो इस तरह के दृष्टिकोण को और अधिक लचीला बनाता है।
संक्षेप में, एडीएल का अर्थ है, जब एक संकलक एक अयोग्य फ़ंक्शन (जैसे नाम स्थान के बिना फ़ंक्शन, जैसे के begin
बजाय std::begin
) का निराकरण करता है , तो यह अपने तर्कों के नामों में घोषित कार्यों पर भी विचार करेगा। उदाहरण के लिए:
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);
इस मामले में, यह कोई फर्क नहीं पड़ता कि योग्य नाम हैं some_lib::begin
और some_lib::end
- चूंकि CustomContainer
बहुत में some_lib::
है, कंपाइलर उन ओवरलोड का उपयोग करेगा count_if
।
यही कारण है using std::begin;
और होने using std::end;
में भी है count_if
। यह हमें अयोग्य का उपयोग करने की अनुमति देता है begin
और end
इसलिए एडीएल के लिए अनुमति देता है और
संकलक को चुनने की अनुमति देता है std::begin
और std::end
जब कोई अन्य विकल्प नहीं मिलते हैं।
हम कुकी खा सकते हैं और कुकी हो सकती है - यानी कस्टम कार्यान्वयन प्रदान करने का एक तरीका है begin
/ end
जबकि कंपाइलर मानक वाले पर गिर सकता है।
कुछ नोट:
उसी कारण से, अन्य समान कार्य हैं: std::rbegin
/ rend
,
std::size
और std::data
।
अन्य उत्तरों का उल्लेख करते हुए, std::
संस्करणों में नग्न सरणियों के लिए अतिभार होते हैं। यह उपयोगी है, लेकिन मैंने जो ऊपर वर्णित किया है उसका केवल एक विशेष मामला है।
std::begin
टेम्प्लेट कोड लिखते समय दोस्तों का उपयोग करना विशेष रूप से अच्छा विचार है, क्योंकि यह उन टेम्प्लेट को अधिक सामान्य बनाता है। गैर-टेम्प्लेट के लिए, जब आप लागू हो, तो बस तरीकों का उपयोग करें।
PS मुझे पता है कि यह पोस्ट लगभग 7 साल पुरानी है। मैं इसके पार आया था क्योंकि मैं एक प्रश्न का उत्तर देना चाहता था जिसे एक डुप्लिकेट के रूप में चिह्नित किया गया था और पता चला कि यहां कोई भी उत्तर ADL का उल्लेख नहीं करता है।