2011-03-01 9 views
12

Siempre trato de incorporar algoritmos STL siempre que puedo, en lugar de escribir bucles manuales. Sin embargo, tengo dificultades para entender cómo std::accumulate es generalmente útil. Cada vez que necesito calcular sumas o promedios, casi siempre termino recurriendo a bucles manuales, porque tengo dificultades para obtener std::accumulate para hacer lo que necesito.Uso de std :: accumulate

El problema es que rara vez tengo un vector simple de enteros que deben sumarse. Usualmente, quiero sumar una matriz de objetos usando una variable de miembro particular. Sí, sé que hay una versión de std::accumulate que toma un BinaryFunction, pero el problema que veo es que esta función tiene que tomar dos valores de tipo T, donde T es el tipo de la suma, en lugar del tipo de la operandos. Tengo problemas para entender cómo esto es útil.

Considere un caso que supongo que es bastante común. Tengo la clase siguiente:

struct Foo 
{ 
    Foo(int cost_, int id_) : cost(cost_), id(id_) 
    { } 

    int cost; 
    int id; 
}; 

Ahora, digo que quiero para calcular la suma de una serie de objetos Foo, utilizando Foo::cost.

quiero decir:

std::vector<Foo> vec; 
// fill vector with values 
int total_cost = std::accumulate(vec.begin(), vec.end(), 0, sum_cost); 

Y sum_cost se define como:

int sum_cost(const Foo& f1, const Foo& f2) 
{ 
    return f1.cost + f2.cost; 
} 

El problema es que esto no funciona porque std::accumulate espera un BinaryFunction que se lleva en dos instancias de la suma resultante tipo - que en este caso es solo int. Pero, ¿cómo es eso útil para mí? Si mi BinaryFunction tiene dos int s, no puedo especificar que quiero sumar el campo cost.

Entonces, ¿por qué está diseñado el std::accumulate de esta manera? ¿Acaso no estoy viendo algo obvio aquí?

+1

Si su clase representa objetos que se pueden acumular, puede considerar agregar operadores + y + =. –

+0

Nitpick: 'std :: accumulate' espera una BinaryFunction, no una BinaryPredicate. Los predicados devuelven un valor booleano. –

+0

@Emile, gracias. Corregido – Channel72

Respuesta

16

estás equivocado acerca operador acumulan teniendo dos del mismo tipo. Lo hace solo si quieres. El uso del operador es específicamente sum = op(sum, *iter). Por lo tanto, su código:

int count = std::accumulate(stuff.begin(), stuff.end(), 0, [](int current_sum, stuff_value_t const& value) { return current_sum + value.member; }); 

Si no puede usar lambda, por supuesto, utiliza los archivadores estándar o boost :: bind.

+0

No marcó este 'C++ 0x' por lo que su uso de lambda es menos que útil. – KitsuneYMG

+0

Hmm, tienes razón. Parece que obtuve información incorrecta de [aquí] (http://www.cplusplus.com/reference/std/numeric/accumulate/ "aquí"), que dice "Operación binaria tomando dos elementos del tipo T como argumento, y devolver el resultado de una operación de acumulación." – Channel72

+3

@Channel - sí. Esa fuente es errónea. –

4

uso funtor:

class F { // sum Foos 
    F(int init = 0); 
    template<class T> 
    Foo operator()(const Foo &a, const T &b) const; 
    operator int() const; 
}; 

int total_cost = std::accumulate(vec.begin(), vec.end(), F(0), F()); 

aviso que puede hacer otras cosas también:

class F { // sum foo values members 
    template<class T> 
    T operator()(const T &a, const Foo &b) const; 
}; 
int total_cost = std::accumulate(vec.begin(), vec.end(), int(0), F()); 
Cuestiones relacionadas