2009-03-06 10 views
7

Necesita una solución más bonita del ejemplo siguiente pero con std :: accumulate.usando de 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

Entonces, ¿por qué no utilizar std :: acumulan? Cuál es exactamente la pregunta? – jalf

+0

@jalf: Buen punto - Me pregunto qué es lo que falta en mi código :) – dirkgently

+0

Acumulate devuelve ¿qué? Pensé que devuelve el mismo tipo de objeto, ¿no? –

Respuesta

11

hacer cambios en la calculadora y la función principal.

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

también podría ser mejor:

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

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

Actualización 2: Boost.Lambda hace de este un juego de niños:

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

Actualización: Esto me ha estado molestando por un tiempo. No puedo hacer que ninguno de los algoritmos de STL funcione de manera decente. Así, rodé mi propia:

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

Por supuesto, la solución original todavía mantiene: Lo más fácil es poner en práctica un operator+. En este caso:

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

y que sea un amigo o miembro de Object (mirar hacia arriba por las que puede preferir uno sobre el otro):

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

y que haya terminado con:

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

Mi enfoque anterior no funciona porque necesitamos un binary_function.

std::accumulate manual.

+0

Gracias por el manual. Pero tu código no compilará –

+0

"resultado" no está inicializado. – MSalters

+0

Creo que el tercer parámetro para acumular debería ser 0, no el resultado. el resultado aún no se ha definido en ese punto. – Ferruccio

0

Es de esperar que esto es tarea ...

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

y

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

asumiendo que no está permitido para tocar la declaración de Objeto.

+0

el resultado de acumular debe ser "doble" y no un "Adaptar" –

1

aquí es un problema aquí, supongo que los argumentos se escriben en el orden equivocado debe ser:

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

en este caso de acumularse, el resultado está contenido en un objeto devuelto.

Si está utilizando el modo paralelo gnu, el administrador le dará problemas si el resultado y el objeto real al que hace referencia el iterador son diferentes.

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

no funcionará con el modo paralelo gnu por algún motivo extraño y tonto.

1

usando 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; 
} 
Cuestiones relacionadas