SORU
10 Temmuz 2013, ÇARŞAMBA


Özel kaplar fonksiyonları bitirmek/begin özgür olmalıdır?

Her zamanki kurallara göre oynayan, özel bir konteyner sınıfı (yani algoritmalar çalışır uslu ile genel kod vs. STL ile çalışır.), oluştururken C 03 yineleyici destek ve üye fonksiyonları bitirmek/begin uygulamak için yeterli oldu.

C 11 döngü ve std için iki yeni kavram menzilli tabanlı tanıtır::başlangıç-bitiş. Aralığı tabanlı C 03 kaplar destek aralığı tabanlı yani döngü için üye işlevleri sona/başlamak anlar, kutudan çıktığı için. Algoritmalar için önerilen yöntem (göre 'modern C kodu' Herb Sutter tarafından) Yazılı std kullanmaktır::üye işlevi yerine başlar.

Ancak, bu noktada sormam gerekiyor - önerilen yol arayıp bir tam begin() fonksiyonu (yani std::begin(c)) veya güvenmek ADL ve aramayı başlatın(c)?

ADL bu durumda işe yaramaz - std beri görünüyor:: (c) c delegeler başlar.(mümkünse) başlamak, her zamanki ADL yararları uygulamak için görünmüyor. Ve eğer herkes ADL güvenmeye başlarsa, tüm özel kaplar ekstra başlamak uygulamak zorunda()/son() gerekli kendi ad ücretsiz işlevleri. Ancak, çeşitli kaynaklardan/son başlamak için niteliksiz çağrılar önerilen yöntem (60 *yani*) olduğunu ima görünüyor.

C 11 yolu nedir? Konteyner kütüphane yazarlar ekstra dersler koşulsuz destek için fonksiyonları bitirmek/begin write ad std; std yokluğunda aramaları bitir/başlamalıdır::başlamak;?

CEVAP
10 Temmuz 2013, ÇARŞAMBA


Çeşitli yaklaşımlar, kendi artıları ve eksileri ile her vardır. Maliyet-fayda analizi ile aşağıda üç yaklaşım.

Özel ADL ile üye olmayan begin() / end()

İlk alternatif sağlar üye olmayan begin() end() fonksiyon şablonları içinde legacy ad güçlendirme gerekli işlevselliği üzerine herhangi bir sınıf veya sınıf şablonu bunu sağlayabilir, ama örneğin yanlış adlandırma kuralları. Kodu çağıran o ADL bu yeni işlevler bulmak için güvenebilirsiniz. Kod (@Xeo tarafından yoruma dayalı) örnek:

// LegacyContainerBeginEnd.h
namespace legacy {

// retro-fitting begin() / end() interface on legacy 
// Container class template with incompatible names         
template<class C> 
auto begin(Container& c) -> decltype(c.legacy_begin())
{ 
    return c.legacy_begin(); 
}

// similarly for begin() taking const&, cbegin(), end(), cend(), etc.

} // namespace legacy

// print.h
template<class C>
void print(C const& c)
{
    // bring into scope to fall back on for types without their own namespace non-member begin()/end()
    using std::begin;
    using std::end;

    // works for Standard Containers, C-style arrays and legacy Containers
    std::copy(begin(c), end(c), std::ostream_iterator<decltype(*begin(c))>(std::cout, " ")); std::cout << "\n";

    // alternative: also works for Standard Containers, C-style arrays and legacy Containers
    for (auto elem: c) std::cout << elem << " "; std::cout << "\n";
}

Artıları:tamamen çalışan tutarlı ve veciz çağırma jenerik

  • herhangi bir Standart Konteyner ve üyesi .begin() .end() tanımlayan kullanıcı tipleri için çalışır
  • C stili diziler için çalışıyor
  • (ayrıca için . için entegre edilebilir ^strong>dizi için döngüler!) herhangi biri içinsınıf şablonuKaynak kodunda değişiklik yapılmasına gerek olmadan .begin() end() üye olmayan legacy::Container<T>

İnş: birçok yerde gerektirir bildirimleri kullanarak

  • std::begin std::end Her kesin arama kapsamı içine taşınmış C stili diziler için seçenekler (şablon başlıkları ve genel rahatsızlık için potansiyel hatadır) geri düşmek gerekli

Özel ile ADL-üye olmayan adl_begin() adl_end()

İkinci bir alternatif olduğu için saklanması kullanarak bildirimlerinin önceki çözüm ayrı bir adl Ad tarafından sağlanması olmayan üye işlev şablonları adl_begin() adl_end(), sonra da bulundu aracılığıyla ADL. Kod (@Yakk tarafından yoruma dayalı) örnek:

// LegacyContainerBeginEnd.h 
// as before...

// ADLBeginEnd.h
namespace adl {

using std::begin; // <-- here, because otherwise decltype() will not find it 

template<class C> 
auto adl_begin(C && c) -> decltype(begin(std::forward<C>(c)))
{ 
    // using std::begin; // in C  14 this might work because decltype() is no longer needed
    return begin(std::forward<C>(c)); // try to find non-member, fall back on std::
}

// similary for cbegin(), end(), cend(), etc.

} // namespace adl

using adl::adl_begin; // will be visible in any compilation unit that includes this header

// print.h
# include "ADLBeginEnd.h" // brings adl_begin() and adl_end() into scope

template<class C>
void print(C const& c)
{
    // works for Standard Containers, C-style arrays and legacy Containers
    std::copy(adl_begin(c), adl_end(c), std::ostream_iterator<decltype(*adl_begin(c))>(std::cout, " ")); std::cout << "\n";

    // alternative: also works for Standard Containers, C-style arrays and legacy Containers
    // does not need adl_begin() / adl_end(), but continues to work
    for (auto elem: c) std::cout << elem << " "; std::cout << "\n";
}

Artıları: tutarlı çağırma tamamen jenerik olarak çalışır

  • @Xeo önerisi için aynı profesyoneller gibi
  • tekrarlanan açıklamalar kullanarak (KURU) kapsüllü olmuştur

İnşküçük bir ayrıntı

  • adl_begin() / adl_end() 24* / end() *kadar kısa ve öz.
  • belki de deyimsel açık olmasına rağmen)
  • C 14 dönüş türü indirimi bekleyen de 26* / std::end *ile isim kirletir

NOT: Eğer bu gerçekten iyileşirse emin değilim önceki yaklaşımı üzerine.

Açıkça std::begin() std::end() Her yerde özellikli

begin() / end() ayrıntı neyse vaz edildikten sonra, neden geristd::begin() / std::end()nitelikli çağrıları gitmiyorsun? Örnek kod:

// LegacyIntContainerBeginEnd.h
namespace std {

// retro-fitting begin() / end() interface on legacy IntContainer class 
// with incompatible names         
template<> 
auto begin(legacy::IntContainer& c) -> decltype(c.legacy_begin())
{ 
    return c.legacy_begin(); 
}

// similary for begin() taking const&, cbegin(), end(), cend(), etc.

} // namespace std

// LegacyContainer.h
namespace legacy {

template<class T>
class Container
{
public:
    // YES, DOCUMENT REALLY WELL THAT THE EXISTING CODE IS BEING MODIFIED
    auto begin() -> decltype(legacy_begin()) { return legacy_begin(); }
    auto end() -> decltype(legacy_end()) { return legacy_end(); }

    // rest of existing interface
};

} // namespace legacy

// print.h
template<class C>
void print(C const& c)
{
    // works for Standard Containers, C-style arrays as well as 
    // legacy::IntContainer and legacy::Container<T>
    std::copy(std::begin(c), std::end(c), std::ostream_iterator<decltype(*std::begin(c))>(std::cout, " ")); std::cout << "\n";

    // alternative: also works for Standard Containers, C-style arrays and
    // legacy::IntContainer and legacy::Container<T>
    for (auto elem: c) std::cout << elem << " "; std::cout << "\n";
}

Artılarıneredeyse jenerik olarak çalışan tutarlı çağırma

  • herhangi bir Standart Konteyner ve üye .begin() .end() tanımlayan kullanıcı tipleri için çalışır
  • C stili diziler için çalışıyor

İnşbiraz ayrıntılı ve güçlendirme ve bakım değil, genel bir sorundur

  • std::begin() / std::end() begin() / end() biraz daha ayrıntılı
  • sadece iş (aynı zamanda için . için entegre edilebilir ^strong>dizi için döngüler!) herhangi biri içinsınıfLegacyContainer üye olmayan .begin() end() (ve kaynak kodu! olduğu için) üye olmayan fonksiyon açık uzmanlık sağlayarak şablonları begin() namespace std 45*
  • sadece üzerine entegre edilebilirsınıf şablonları47* *doğrudanbegin() / end() LegacyContainer<T> şablonları için kullanılabilir) kaynak kod içinde üye işlevler ekleyerek. namespace std hile işlev şablonları kısmen özel olamaz çünkü burada çalışmıyor.

Kullanmak ne?

ADL yaklaşımı ile üye olmayan begin() / end() bir kapsayıcı kendi ad olduğu deyimsel C 11 yaklaşım, özellikle genel işlevleri gerektirir güçlendirme üzerinde eski sınıflar ve sınıf şablonları. Kullanıcı sağlayan üye olmayan swap() fonksiyonlar için aynı deyim.

Kod için tek Standart Konteyner kullanır veya C stili diziler std::begin() std::end() her yerde daha ayrıntılı aramalar pahasına kullanarak bildirimleri, tanıtmadan denilebilir. Bu yaklaşım bile entegre edilebilir ama namespace std (sınıf türleri için) veya-kaynak modifcations (sınıf şablonları) ile işe yaramaz gerektirir. Bu yapılabilir, ama bu bakım sıkıntıya değmez.

Olmayan genel kod, nerede konteyner soru bilinen kodlama zamanı, bir tane bile itimat ADL için Standart Kaplar sadece ve açıkça hak std::begin / std::end C-tarzı diziler. Bazı arama tutarlılığı kaybeder ama kullanarak bildirimleri kaydeder.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • FD2097

    FD2097

    21 HAZİRAN 2009
  • Jeremy Gallman

    Jeremy Gallm

    11 NİSAN 2012
  • SuppressedStorm

    SuppressedSt

    11 AĞUSTOS 2013