2009-03-06 12 views
7

Potrzebujesz ładniejszego rozwiązania poniższego przykładu, ale ze std :: akumuluj.używanie std :: akumuluj

#include <algorithm> 
#include <vector> 
#include <iostream> 

class Object 
{ 
public: 
    Object(double a, double b): 
     a_(a), 
     b_(b) 
    {} 

    double GetA() const { return a_; } 
    double GetB() const { return b_; } 
    // other methods 
private: 
    double a_; 
    double b_; 
}; 

class Calculator 
{ 
public: 
    Calculator(double& result): 
     result_(result) 
    {} 

    void operator() (const Object& object) 
    { 
     // some formula 
     result_ += object.GetA() * object.GetB(); 
    } 
private: 
    double& result_; 
}; 

int main() 
{ 
    std::vector<Object> collection; 
    collection.push_back(Object(1, 2)); 
    collection.push_back(Object(3, 4)); 

    double result = 0.0; 
    std::for_each(collection.begin(), collection.end(), 
        Calculator(result)); 

    std::cout << "result = " << result << std::endl; 

    return 0; 
} 
+0

Więc dlaczego nie można użyć std :: zgromadzić? Czym dokładnie jest pytanie? – jalf

+0

@jalf: Dobra uwaga - zastanawiam się, co jest takiego, czego brakuje w moim kodzie :) – dirkgently

+0

Skumulowany zwraca co? Myślałem, że zwraca ten sam typ co obiekt, nie? –

Odpowiedz

11

zmiany w kalkulatorze i głównej funkcji.

struct Calculator 
{ 
    double operator() (double result, const Object& obj) 
    { 
     return result + (obj.GetA() * obj.GetB()); 
    } 

}; 

int main() 
{ 
    std::vector<Object> collection; 
    collection.push_back(Object(1, 2)); 
    collection.push_back(Object(3, 4)); 

    double result = std::accumulate(collection.begin(), collection.end(), 0, Calculator()); 
    std::cout << "result = " << result << std::endl; 

    return 0; 
} 

też mogłoby być lepiej:

double sumABProduct(double result, const Object& obj) 
{ 
    return result + (obj.GetA() * obj.GetB()); 
} 

double result = std::accumulate(collection.begin(), collection.end(), 0, sumABProduct); 
3

Aktualizacja 2: Boost.Lambda sprawia, że ​​to bułka z masłem:

// headers 
#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/bind.hpp> 
using namespace boost::lambda; 
// ... 
cout << accumulate(dv.begin(), dv.end(), 
        0, 
        _1 += bind(&strange::value, _2)) //strange defined below 
    << endl; 

Aktualizacja: Zostało podsłuch mnie na chwilę. Nie mogę po prostu uzyskać żadnego z algorytmów STL do pracy w przyzwoity sposób. Więc walcowane moje własne:

// include whatever ... 
using namespace std; 

// custom accumulator that computes a result of the 
// form: result += object.method(); 
// all other members same as that of std::accumulate 
template <class I, class V, class Fn1, class Fn2> 
V accumulate2(I first, I last, V val, Fn1 op, Fn2 memfn) { 
    for (; first != last; ++first) 
     val = op(val, memfn(*first)); 
    return val; 
} 

struct strange { 
    strange(int a, int b) : _a(a), _b(b) {} 
    int value() { return _a + 10 * _b; } 
    int _a, _b; 
}; 

int main() { 
    std::vector<strange> dv; 
    dv.push_back(strange(1, 3)); 
    dv.push_back(strange(4, 6)); 
    dv.push_back(strange(20, -11));   
    cout << accumulate2(dv.begin(), dv.end(), 
         0, std::plus<int>(), 
         mem_fun_ref(&strange::value)) << endl; 
} 

Oczywiście, oryginalne rozwiązanie nadal posiada: Najłatwiej jest wdrożenie operator+. W tym przypadku:

double operator+(double v, Object const& x) { 
     return v + x.a_; 
} 

i sprawiają, że przyjaciel lub członek Object (sprawdzić, dlaczego może wolisz jeden nad drugim):

class Object 
{ 
    //... 
    friend double operator+(double v, Object const& x); 

i skończysz z:

result = accumulate(collection.begin(), collection.end(), 0.0); 

Moje wcześniejsze podejście nie działa, ponieważ potrzebujemy binary_function.

std::accumulate podręcznik.

+0

Dzięki za instrukcję. Ale twój kod się nie skompiluje. –

+0

"Wynik" nie został zainicjowany. – MSalters

+0

Myślę, że trzeci parametr do akumulacji powinien wynosić 0, a nie wynik. wynik nie został jeszcze zdefiniowany w tym momencie. – Ferruccio

0

Jeden byłby nadzieję, że to praca domowa ...

struct Adapt { 
    static double mul(Object const &x) { return x.GetA() * x.GetB(); } 
    static double operator()(Object const &x, Object const &y) { 
     return mul(x)+mul(y); } }; 

i

result = std::accumulate(collection.begin(), collection.end(), Object(0,0),Adapt()); 

zakładając, że nie wolno dotknąć deklaracji Obiektu.

+0

wynik kumulacji powinien być "podwójny", a nie "Dostosować" –

1

tutaj jest problem tutaj, myślę, że argumenty są napisane w niewłaściwej kolejności powinny być:

result = std::accumulate(collection.begin(), collection.end(), Object(0),Adapt()) 
where Adapt is defined thus: 

struct Adapt { 
    static double mul(Object const &x) { return x.GetA() * x.GetB(); } 
    static Object operator()(Object const &x, Object const &y) { 
     return Object(mul(x)+mul(y)) ; } }; 

w tym przypadku akumuluj, wynik jest zawarty w zwrócony obiekt.

Jeśli używasz gnu w trybie równoległym, funktor daje ci problemy, jeśli wynik i rzeczywisty obiekt, do którego odnosi się iterator, są różne.

struct Adapt { 
     static double mul(Object const &x) { return x.GetA() * x.GetB(); } 
     static double operator()(Object const &x, Object const &y) { 
      return mul(x)+mul(y) ; } }; 
result = std::accumulate(collection.begin(), collection.end(), 0.0,Adapt()) 

nie będzie działał w trybie równoległym dla gnu z jakiegoś dziwnego i głupiego powodu.

1

Korzystanie C++ 0x:

#include <numeric> 
#include <vector> 
#include <iostream> 

class Object 
{ 
    public: 
    Object(double a, double b): 
     a_(a), 
     b_(b) 
     {} 

    double GetA() const { return a_; } 
    double GetB() const { return b_; } 
    // other methods 
    private: 
    double a_; 
    double b_; 
}; 

int main() 
{ 
    std::vector<Object> collection; 
    collection.push_back(Object(1, 2)); 
    collection.push_back(Object(3, 4)); 
    double result = std::accumulate(collection.begin(), collection.end(), 0, 
            [] (double result, const Object& obj) 
            { 
             return result + obj.GetA() * obj.GetB(); 
            } 
            ); 

    std::cout << "result = " << result << std::endl; 

    return 0; 
} 
Powiązane problemy