2012-07-01 11 views
10

Ben std::istream_iterator<std::string> 'ın begin() ve end() olarak tanımlanan buNeden std :: istream_iterator için başlangıç ​​ve bitiş aşırı yüklerimi bulmak için aralık yok?

std::ifstream file(filename, std::ios_base::in); 
if(file.good()) 
{ 
    file.imbue(std::locale(std::locale(), new delimeter_tokens())); 
    for(auto& entry : std::istream_iterator<std::string>(file)) 
    { 
     std::cout << entry << std::endl;  
    } 
} 
file.close(); 

gibi kod Mark Nelson da Dr Dobb en here yaklaşık yazmıştır budur

template<class T> 
std::istream_iterator<T> begin(std::istream_iterator<T>& stream) 
{ 
    return stream; 
} 

template<class T> 
std::istream_iterator<T> end(std::istream_iterator<T>& stream) 
{ 
    return std::istream_iterator<T>(); 
} 

izler var. Ne yazık ki, kod hata mesajları

hata C3312 ile benim Visual Studio 2012 tarihinde derlenmeyecektir: tipi için bulunamadı çağrılabilir 'başlamak' fonksiyonunu 'std :: istream_iterator < _Ty>'

ve

hata C3312: tipi için bulunamadı çağrılabilir 'end' işlevi 'std :: istream_iterator < _Ty>'

Soru: Fark etmediğim bir şey var mı, derleyicide hata var (olası değil, fakat durum böyle) veya ... Peki, herhangi bir fikir mi?


Bu sorular, Xeo tarafından önerildiği gibi önemli ölçüde temizlenmiştir. Daha fazla arka plan ve referanslar sağlamak için bu Stackoverflow üzerinde benim other question ile ilgili, ben her zamanki döngülerden satır tabanlı ayrıştırma temizleyici yapmak için nasıl merak ediyordum.

std::ifstream file(filename, std::ios_base::in); 
if(file.good()) 
{    
    file.imbue(std::locale(std::locale(), new delimeter_tokens())); 
    for(auto& entry : istream_range<std::string>(file) 
    { 
     std::cout << entry << std::endl;  
    } 
} 
file.close(); 

izler ama giderilmesi için çalıştı ufak bir engelle olduğu gibi kodlama ve internetten kontrol etme ve Biraz ben bir çalışma taslağını vardı. Ben derlemek ve

for(auto& entry : istream_range<std::string>(file) 

, farklı Yineleyici dikkate alınız gibi değil başarısız kodda olduğu gibi yazmaya daha doğal görünecektir düşünüyorum. delimeter_tokens, Nawaz gibi tanımlanmıştır, here (kod çoğaltılmamış) ve istream_range, Code Synthesis blog here'da gösterildiği gibi gösterilmiştir. Başlama ve son uygulamaların, yukarıda bahsedilen Code Synthesis blog yazısında (
) bildirildiği gibi çalışması gerektiğini düşünüyorum. Son kural (serbest duran başlangıç ​​() ve bitiş() işlevlerinin geri dönüşü) mevcut bir kapsayıcıyı invaziv olmayan şekilde uyarlamamıza izin verir. döngü arabirimi için aralık tabanlı.

Bu nedenle, tüm ilgili (ilgili) arka planla ilgili sorum.

+0

sordum gerçek soru yansıtacak şekilde soru başlığı değiştirmek için özgürlük aldı. Geri sarın ya da gerekirse değiştirin. – Xeo

+0

Böyle daha iyi, bence. Benimkine benzer bir çözüm arayışında olanların ve çözülmesi gereken arama sorununa sahip olanların dikkatini çekiyor. Gönderinizi nasıl bir cevap olarak (veya daha başarılı bir kişi yapar) yapabilirim? – Veksi

+0

Bunun için de teşekkürler! : D – Veksi

cevap

7

Yerel dizi için özel işlem (T foo[N]) ve üye begin/ hiçbir sonuç sağlamazsa, ADL'ye göre değişen değer kullanılır.

§6.5.4 [stmt.ranged] p1

  • aksi takdirde başlamak-expr ve begin ve endargüman bağımlı arama ile aranmasıdır olan begin(__range) ve sırasıyla end(__range), sonu expr (3.4.2. Bu ad arama amaçları için std ad alanı ilişkili bir ad alanıdır.

Senin sorunun std::istream_iterator ilişkili ad (besbelli) namespace std değil, genel ad olduğunu vardır. işlev çağrısında her bir bağımsız değişken tip T için

§3.4.2 [basic.lookup.argdep] p2

, dikkat edilmesi gereken, sıfır ya da daha fazla ilişkili ad alanları bir dizi ve sıfır veya daha fazla ilişkili sınıflardan oluşan bir küme mevcuttur. Ad alanları ve sınıf kümeleri, tamamen işlev argümanlarının türlerine göre belirlenir [...].

  • T temel bir türse, ilişkili ad ve sınıf kümeleri boştur.
  • T, (birlikler dahil) sınıfıysa, ilişkili sınıflar şunlardır: sınıfın kendisi; Varsa, üyesi olan sınıf; ve doğrudan ve dolaylı temel sınıfları. İlişkili ad alanları, ilişkili sınıfların üyeleri oldukları ad alanlarıdır. Ayrıca, T bir sınıf şablon uzmanlığıysa, ilişkili ad alanları ve sınıfları aşağıdakileri de içerir: şablon tipi parametreleri [...] için sağlanan şablon argümanlarının türleriyle ilişkili ad alanları ve sınıflar.

Not ikinci merminin son (alıntı) parçası. Temelde şablon argüman olarak genel ad üyesi olan bir sınıf kullanarak kod iş yapar anlamına gelir:

#include <iterator> 
#include <iostream> 

template<class T> 
std::istream_iterator<T> begin(std::istream_iterator<T> is){ 
    return is; 
} 
template<class T> 
std::istream_iterator<T> end(std::istream_iterator<T>){ 
    return std::istream_iterator<T>(); 
} 

struct foo{}; 

std::istream& operator>>(std::istream& is, foo){ 
    return is; 
} 

int main(){ 
    for(foo f : std::istream_iterator<foo>(std::cin)) 
    //        ^^^ 
    // make global namespace one of the associated namespaces 
    ; 
} 
+0

Seni şimdi takip edemiyorum. Dosya akışından tokenized dizeleri okumam gerekiyorsa ad alanı ilişkilendirmesi nasıl çalışır? Yani, döngüde işaret ettiğin foo benim durumumda dizeler olmalı. – Veksi

+0

@Veksi: Temel olarak, cevabımın yalnızca ilk kısmı önemlidir: "std" üyeleri için aşırı yük için global ad alanında aşırı yükleme yapamazsınız. İkinci bölüm, sadece çalışmasına izin verecek bir ADL quirkyness'i sergilemek içindi. : P – Xeo

+1

[Bu Soru-Cevap] 'ya yorum yaparken (http://stackoverflow.com/a/18321288/819272), [* core issue * 1442] (http://wg21.cmeerw.net/cwg/ hakkında bilgi aldım) issue1442) kuralları biraz değiştirir. Ad alanı 'std' artık ilişkili bir ad alanı değildir ve [* açıkça belirtilmiştir *] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3691.pdf)" başlar ve bitiş ile ilişkili ad alanlarında (3.4.2) bakın. [Not: Sıradan tekdüze arama (3.4.1) gerçekleştirilmez. - bitiş notu] " – TemplateRex

1

Bağımsız değişken bağımlı arama nedeniyle derleyici, ad alanında begin() ve end() bulmaya çalışır. Orada fonksiyonlarınızı koyarsanız, kod derler.

C++'da ad araması karmaşık bir sorun olduğundan, derleyicinin doğru şekilde davranıp davranmadığından emin değilim.

+1

"namespace std" ye aşırı yüklenme yetkiniz yok. – Xeo

+0

Ancak şablonlarda uzmanlaşabilirsiniz, hayır? – jrok

+2

@jrok: Evet, ancak sadece kullanıcı tanımlı tipler için, std'den (IIRC) kaynaklanan tipler için değil. Ayrıca, * kısmen * fonksiyon şablonlarını uzmanlaştıramazsınız ve genel olarak fonksiyon şablonu uzmanlığı çatlamaz. – Xeo

İlgili konular