2009-03-06 10 views
7

Sono necessarie soluzioni più carine nell'esempio seguente ma con std :: accumulate.utilizzo di std :: accumulate

#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

Allora perché non si utilizza std :: si accumulano? Qual è esattamente la domanda? – jalf

+0

@jalf: buon punto - Mi chiedo cosa manca il mio codice :) – dirkgently

+0

Acumulate restituisce cosa? Pensavo che restituisse lo stesso tipo di un oggetto, no? –

risposta

11

fare modifiche in Calcolatrice e funzione principale.

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; 
} 

anche potrebbe essere meglio:

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

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

Aggiornamento 2: Boost.Lambda rende questo un pezzo di torta:

// 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; 

Aggiornamento: Questo è stato bugging me per un po '. Non riesco a far funzionare nessuno degli algoritmi STL in maniera decente. Così, ho arrotolato la mia:

// 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; 
} 

Naturalmente, la soluzione originale vale ancora: Il metodo più semplice è quello di implementare un operator+. In questo caso:

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

e ne fanno un amico di Object o membro (guardare in alto perché si può scegliere uno sopra l'altro):

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

e il gioco è fatto con:

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

Il mio approccio precedente non funziona perché abbiamo bisogno di un binary_function.

std::accumulate manuale.

+0

Grazie per il manuale. Ma il tuo codice non verrà compilato. –

+0

"risultato" non è inizializzato. – MSalters

+0

Penso che il terzo parametro da accumulare dovrebbe essere 0 non risultato. il risultato non è ancora stato definito a quel punto. – Ferruccio

0

Si potrebbe sperare questo è compiti ...

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); } }; 

e

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

supponendo che non ti è permesso toccare la dichiarazione dell'oggetto.

+0

il risultato dell'accumulo dovrebbe essere 'double' e non un 'Adapt' –

1

qui è un problema qui, immagino che gli argomenti sono scritti in ordine errato dovrebbe essere:

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)) ; } }; 

in questo caso di accumulo, il risultato è contenuto in un oggetto restituito.

Se si utilizza la modalità parallela di gnu, il funtore ti darà problemi se il risultato e l'oggetto reale a cui fa riferimento l'iteratore sono diversi.

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()) 

non funziona con la modalità parallela di GNU per qualche motivo strano e sciocco.

1

utilizzando 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; 
} 
Problemi correlati