Bir faydası std::begin
vestd::end
dış sınıflar için standart arayüz uygulamak için uzatma noktaları olarak hizmet vermeleridir.
Kullanmak isterseniz CustomContainer
ile sınıf beklediği döngü veya şablon işlevi için aralık tabanlı .begin()
ve .end()
yöntemleri, belli ki bu yöntemleri uygulamak gerekir.
Sınıf bu yöntemleri sağlarsa, bu bir sorun değildir. Bunu yapmadığında, değiştirmeniz gerekir *.
Bu, her zaman mümkün değildir, örneğin harici kütüphane, özellikle ticari ve kapalı kaynak olan.
Böyle durumlarda std::begin
ve std::end
kullanışlı, çünkü sınıfın kendisini değiştirmeden yineleyici API'si sağlayabilir, ancak serbest fonksiyonları aşırı yükleyebilir.
Örnek:count_if
bir çift yineleyici yerine bir kapsayıcı alan bir işlevi uygulamak istediğinizi varsayalım . Böyle bir kod şöyle görünebilir:
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));
}
Şimdi, bu gelenekle kullanmak istediğiniz herhangi bir sınıf için count_if
, bu sınıfları değiştirmek yerine yalnızca iki ücretsiz işlev eklemeniz gerekir.
Şimdi, C ++, Bağımsız Değişken Bağımlı Arama adlı bir mekanizmaya sahip
(ADL) sahip ve bu yaklaşımı daha da esnek hale getiriyor.
Kısacası, ADL, bir derleyici niteliksiz bir işlevi çözdüğünde (örneğin, begin
yerine ad alanı olmayan işlev std::begin
), bağımsız değişkenlerinin ad alanlarında bildirilen işlevleri de dikkate alacağı anlamına gelir . Örneğin:
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);
Bu durumda, nitelikli adların olması önemli değildir some_lib::begin
ve some_lib::end
- çünkü içinde CustomContainer
olduğu için some_lib::
derleyici bu aşırı yükleri kullanacaktır.count_if
.
Bu da sahip sebebi var using std::begin;
ve using std::end;
içinde count_if
. Bu, kalifiye olmayan kullanmamıza izin verir begin
ve end
bu nedenle ADL'ye
izin verir ve derleyicinin seçmesine std::begin
ve std::end
başka alternatif bulunmadığına izin verir .
Biz çerez yiyip çerez olabilir - yani özel bir uygulama sağlamak için bir yol var begin
/ ' end
derleyici standart olanları geri düşebilir iken.
Bazı notlar:
Aynı nedenden ötürü, benzer başka işlevler de vardır: std::rbegin
/ rend
,
std::size
ve std::data
.
Diğer cevaplardan bahsedildiği gibi, std::
versiyonlar çıplak diziler için aşırı yüklenmelere sahiptir. Bu yararlıdır, ancak yukarıda tarif ettiğim şeyin özel bir örneğidir.
std::begin
Şablon kodu yazarken ve arkadaşlarını kullanmak özellikle iyi bir fikirdir, çünkü bu, bu şablonları daha genel hale getirir. Şablon olmayanlar için de geçerliyse yöntemleri de kullanabilirsiniz.
PS: Bu yazının yaklaşık 7 yaşında olduğunun farkındayım. Karşıya çıktım çünkü yinelenen olarak işaretlenen ve burada hiçbir cevabın ADL'den bahsetmediğini keşfettiği bir soruyu cevaplamak istedim.