2012-11-13 16 views
16

Yineleyici verildiğinde, bu yineleyicinin başvurduğu koleksiyon için doğru karşılaştırma işlevini almak/kullanmak mümkün mü?Bir iteratör verilen içindekinin karşılaştırma işlevi geri alma

Örneğin, ben genel bir algoritma yazıyorum varsayalım:

Şimdi
template <class InIt, class T> 
void do_something(InIt b, InIt e, T v) { 
    // ... 
} 

, ı [b..e) içinde v bulmak gibi basit bir şey yapmak istiyorum diyelim. b ve e, std::vector üzerindeki yineleyiciler ise, if (*b == v) ...'u kullanabilirim. Bununla birlikte, b ve e'un std::map üzerinden yineleyiciler olduğunu varsayalım. Bu durumda, yalnızca anahtarını anahtarıyla karşılaştırınız, haritadaki değerlerin tamamını değil.

Soru şu ki, bu yineleyiciler haritaya verildiğinde, o haritanın yalnızca tuşları karşılaştıracak karşılaştırma işlevini nasıl alırım? Aynı zamanda, map ile çalıştığımı da körü körüne söylemek istemiyorum. Örneğin, yineleyiciler bir set işaret ettiyse, o set için tanımlanan karşılaştırma işlevini kullanmak isterim. Bir vector veya deque işaret ettiyseler, muhtemelen == kullanmam gerekir, çünkü bu kapsayıcıların tanımlı bir karşılaştırma işlevi yoktur.

Ah, neredeyse unuttum: Ben birçok durumda, bir kap sadece içerdiği elementler için operator< yerine operator== bir eşdeğer olacaktır fark - Bunu kullanmak mümkün olan gayet de değilim.

+0

Hiçbir zaman elimizde bir cevap yazmak için ama bu http://en.cppreference.com/w/cpp/container/map/key_comp yardımcı olabilir. Hmm, çok değil. Zor kısmı konteyneri alıyor. –

+0

"set" durumunuz için kafam karıştı. Bir 'set'in karşılaştırıcısının, 'operatör ==' için geçerli olmayan toplam sıra olması gerekir. – pmr

+0

Bir harita girişinin anahtarını yalnızca veya tüm girişle karşılaştırırsanız, aynı şey aynı değil mi? [Düzenle] Tabii ki boş değil - haritalanmış kısımda eşitlik işleminiz olmayabilir. –

cevap

6

Bir yineleyiciden alttaki kapsayıcı türüne (standart bir kapsayıcı varsa) eşleme yapmanın standart bir yolu yoktur. Hangi kapsayıcıyı belirlemeye çalışmak için bazı sezgisel yöntemler kullanabilirsiniz, ancak bu da basit olmayacak ve muhtemelen garanti edilmeyecektir. * Value_type * Bu bir std::map olabileceğine dair bir ipucu olan std::pair<const K, T> ve türlerini K ve T ayıklanması sonra ister

Örneğin, tip olup olmadığını belirlemek için bir üst-işlevin kullanılacağını belirlemek için bir üst-işlevin deneyin kullanabilirsiniz yineleyicinin ve X, Y'un belirli bir kombinasyonu için std::map<K,T,X,Y>::iterator veya std::map<K,T,X,Y>::const_iterator türünün eşleşmesi. belirlemek için yeterli olabilir haritanın durumunda

(yani başarı şansı yüksek olan tahmin) yineleyici bir std::map ifade ettiği, ancak dahi o kullanabilir ve hatta ayıklayabileceğinden unutmamalıdır Karşılaştırıcının X tipini, çoğaltıcısını genel durumda karşılaştırmak için yeterli değildir. Nadiren (ve tavsiye edilmeyen) karşılaştırıcıların durumu olabilir ve doğrudan konteynere erişimi olmayan karşılaştırıcının özel durumu nedir bilmezsiniz.Ayrıca orada std::vector<> bazı uygulamalarda sezgisel bu tip bile yardımcı olmaz vakalar vardır yineleyici tipi doğrudan bir işaretçi ve bu durumda bir std::vector<> içine diziye bir 'yineleyici' ve bir yineleyici ayırt edemez dikkat aynı temeldeki türlerden.

11

Yineleyiciler kapsayıcılara bağlı olmak zorunda değildir, bu nedenle, bağlı olmadıkları kaplar hakkında size herhangi bir ayrıntı vermezler. Bu, temel yineleyici soyutlamasıdır: yineleyiciler, dizinin nereden geldiğine bakılmaksızın dizileri sınırlar. Kaplar hakkında bilgi sahibi olmanız gerekiyorsa, kapsayıcı alan algoritmalar yazmanız gerekir.

+2

Örnek: Bazı 'string' ve' vector', iterator'leri çıplak işaretçiler olarak uyguladı (sıralı ve bitişik temeldeki arabelleğin avantajlarından yararlanarak). –

+0

Kapsayıcıları argüman olarak alsanız bile, hala bir “İlişkilendirme” öğesini bir “AssociativeContainer” dan ayırt etmek için hilelere güvenmeniz gerekir. Sanırım güvenilir bir şekilde çalışan bir 'is_associative_container 'yazmak zor. – pmr

+0

@pmr: Bu özellik aslında sadece standart kapsayıcıları desteklemek istiyorsanız basittir ... sadece türün std :: map', std :: multimap, std :: set türlerinden biri olup olmadığını belirlemeniz gerekir. '' 'std :: multiset' (ve * karşılaştırıcı * kavramı o kadar açık olmasa da bunları desteklemeniz gerekiyorsa, sıralanmamış sürümler) –

3

Maalesef yineleyiciler hep (bazen hiç bir standart kap içinde değildir ve) bulundukları kabın bilmem. iterator_traits bile, yalnızca size nasıl karşılaştırılacağını söylemeyen value_type hakkında bilgi içerir. Bunun yerine standart kitaplıktan ilham alalım. Tüm ilişkisel kapsayıcılar (map, vb), std::find kullanmak yerine kendi find yöntemlerine sahiptir. Ve 'un böyle bir kapta std::find kullanması gerekiyorsa, find_if'u kullanmazsınız.

Çözümünüzün, birleşik kapsayıcılar için, girdilerin nasıl karşılaştırılacağını belirten bir yüklemeyi kabul eden bir do_something_if'a ihtiyacınız olduğu anlaşılıyor.