2010-07-08 4 views
10

Şu nesneye sahip olduğumu varsayalım:Bir kapsayıcıdaki tüm öğeler için üye işlevinin sonucunu özetlemenin en iyi yolu nedir?

struct Foo 
{ 
    int size() { return 2; } 
}; 

vector<Foo> içindeki tüm nesnelerin toplam size değerini elde etmek için en iyi yol nedir (en çok okunabilir, okunabilir, vs.)? Çözümümü göndereceğim ama daha iyi fikirlerle ilgileniyorum.

Şu ana kadar elimizde:

  • std :: birikir ve bir xx xx xxx xdx40 std :: birikir ve bir lambda ifadesi
  • düz ol 'for-loop

Başka uygulanabilir çözümler var mı? Xzx25 veya std::bind1st/2nd kullanarak bir şeyleri sürdürülebilir kılabilir misiniz?

+3

'std :: vektör vec için tabanlı aralığı; vec.size() * 2', çünkü 'Foo :: size' kelimesinin her zaman 2 değerini döndürdüğünü biliyoruz. :) – jalf

cevap

23

, bu kısa bir halini kullanabilirsiniz: aşağı-toprak çözüm İşte

std::vector<Foo> vf; 

// do something to populate vf 


int totalSize = std::accumulate(vf.begin(), 
           vf.end(), 
           0, 
           [](int sum, const Foo& elem){ return sum + elem.size();}); 
+0

yazım hatası: lambda'nın gövdesinin sonunda bir noktalı virgül eksik (kendimi düzenleyemiyorum). – rafak

7

std::accumulate ve bir functor kullanın. sizin derleyici C++ 0x lambda ifadeleri destekliyorsa kendi öneriye ek olarak

#include <functional> 
#include <numeric> 

struct SumSizes : public std::binary_function<int, Foo, int> 
{ 
    int operator()(int total, const Foo& elem) const 
    { 
     return total + elem.size(); 
    } 
}; 

std::vector<Foo> vf; 

// do something to populate vf 

int totalSize = std::accumulate(vf.begin(), 
           vf.end(), 
           0, 
           SumSizes()); 
+0

Çözümünüz elbette ki en aptalca olanıdır, ancak bu basit durumlarda aptal bir yineleyici döngüsü daha kolay olabilir. – Philipp

+0

+1 Bu, tüm standart kapsayıcıların bir 'size()' üye işlevine sahip olduğundan, genel amaçlı 'SumSizes' ayarlanarak geliştirilebilir. –

+0

@Jon, Sanırım soruyu yanlış anlamış olabilirsiniz. Nokta, kabın büyüklüğünü elde etmek değil, tüm elemanların bir üye fonksiyonunun sonucunu toplamaktı. Belki de 'boyut' böyle bir işlev için zayıf bir isimdi. –

4

geçerli:

typedef std::vector<Foo> FooVector; 
FooVector vf; 
int totalSize = 0; 
for (FooVector::const_iterator it = vf.begin(); it != vf.end(); ++it) { 
    totalSize += it->size(); 
} 
+0

Diğer, fonksiyonel çözümlerden okumak çok daha kolay. – Jon

7

Boost yineleyici zerafetlerini buluyorum, ancak bunlar biraz ayrıntılı olabilir (aralık tabanlı algoritmalar bunu daha iyi yapar). Bu durumda transform iterators işi yapabilir:

#include <boost/iterator/transform_iterator.hpp> 
//... 

int totalSize = std::accumulate(
    boost::make_transform_iterator(vf.begin(), std::mem_fn(&Foo::size)), 
    boost::make_transform_iterator(vf.end(), std::mem_fn(&Foo::size)),0); 

Edit: "std::mem_fn(&Foo::size)"

Düzenleme tarafından "boost::bind(&Foo::size,_1)" değiştirilir: Sadece Boost.Range kütüphane aralığı algoritmaları tanıtmak için güncellendi bulundu!

#include <boost/range/distance.hpp> // numeric.hpp needs it (a bug?) 
#include <boost/range/numeric.hpp> // accumulate 
#include <boost/range/adaptor/transformed.hpp> // transformed 
//... 
int totalSize = boost::accumulate(
    vf | boost::adaptors::transformed(std::mem_fn(Foo::size)), 0); 

Not: performansları yaklaşık aynıdır (yorumumu bakınız): Burada aynı çözümün yeni bir sürümüdür içten, transformedtransorm_iterator kullanır. (Ötesinde) C++ 11 kullanılarak

+1

Bu çözümü ve doğrudan birini karşılaştıran zamanlamalar yaptım ve maalesef bu daha yavaş (2 ile 5 arasında bir faktör buldum). Ancak bu bir endişe olmayabilir. – rafak

+0

Bence bu en iyi cevap. Sorun, ** ne ** bir özel yineleyici tarafından ele alınır, ne **, nasıl bir biriktirici kullanılarak ele alınır, nasıl ** biriktirilir. İstediğiniz varsayılan biriktirme davranışı (artı) _is_. Bu sorunu içsel ürüne genişletmeyi düşünün: dönüştürücü yineleyici yeniden kullanılabilir, ancak bu süre, functor değildir. Varsayılan algoritmayı üye boyutu() açısından yeniden tanımlamak için her algoritma için yeni bir funger gerekli olacaktır. –

4

döngü

std::vector<Foo> vFoo; 
// populate vFoo with some values... 
int totalSize = 0; 
for (const auto& element: vFoo) { 
    totalSize += element.size(); 
} 
İlgili konular