También puede separar la funcionalidad 'tomar segundo de par' de 'calcular MULT * VAL' y 'agregar algo a un acumulador'.
Aunque no necesita impulso para hacer esto, ya crearon una gran cantidad de un marco de programación 'funcional'. Si no puedes usar boost, necesitas un poco de magia de plantilla. No también complicado, sin embargo.
#include <map>
#include <algorithm>
#include <numeric>
#include <functional>
#include <iostream>
Ahora considero que es mejor poner la multiplicación dentro de la clase.
struct SMyStruct
{
int MULT;
int VAL;
long f() const { return MULT*VAL; }
};
Crear un funtor genérico de 'tomar el segundo del par':
// a 'take-second' functor
template< typename at_pair >
struct to_second_t : public std::unary_function< at_pair, typename at_pair::second_type > {
const typename at_pair::second_type& operator()(const at_pair & p) const {
return p.second;
}
};
Esto parece complicado, pero no es más que una forma genérica de decir: 'primero hacer esto, a continuación, hacer eso con el resultado ':
// compose two functors (simplified)
template< typename at_F, typename at_G >
struct compose_t : public std::unary_function< typename at_F::argument_type, typename at_G::result_type >{
at_F f;
at_G g;
compose_t(at_F& f, at_G& g): f(f), g(g) {}
typename at_G::result_type operator()(const typename at_F::argument_type& v) const {
return g(f(v));
}
};
template< typename at_F, typename at_G >
compose_t<at_F, at_G> compose(at_F& f, at_G& g) { return compose_t<at_F,at_G>(f, g); }
// compose two functors (a unary one, and a binary one)
//
template< typename at_F, typename at_G >
struct compose2_t : public std::binary_function< typename at_F::first_argument_type, typename at_G::argument_type, typename at_G::result_type >{
at_F f;
at_G g;
compose2_t(at_F& f, at_G& g): f(f), g(g) {}
typename at_G::result_type operator()(const typename at_F::first_argument_type& a1, const typename at_G::argument_type& v) const {
return f(a1, g(v));
}
};
template< typename at_F, typename at_G >
compose2_t<at_F, at_G> compose2(at_F& f, at_G& g) { return compose2_t<at_F,at_G>(f, g); }
Y, por último, poner todo en la práctica:
int main()
{
typedef std::map<int, SMyStruct > tMap;
tMap m;
SMyStruct s = {1,2};
m[1].VAL = 1; m[1].MULT = 3;
m[2].VAL = 2; m[2].MULT = 10;
m[3].VAL = 3; m[3].MULT = 2;
// mind, this is not LISP (yet)
long total = std::accumulate(m.begin(), m.end(), 0,
compose2(
std::plus<int>(),
compose(
to_second_t<tMap::value_type>(),
std::mem_fun_ref(&SMyStruct::f)))
);
std::cout << "total: " << total <<std::endl;
return 0;
}
Aw, bb, pásenme la respuesta, así que voy a ser un poco pedante en su lugar: sabes que los guiones bajos principales son generalmente una mala idea, ¿no? (reservado para la implementación en la mayoría de los casos) Y el prefijo S en una estructura es un ruido completamente sin sentido. :) – jalf
argh, ok ... Bueno, siempre prefijamos estructuras con S y clases con C; nuestros mandatos estándares de codificación. En cuanto a "_", estoy de acuerdo, pero como no era parte de nada, lo dejé como tal. Normalmente uso m_ para miembros g_ para globales y s_ para estáticos. Gracias por mencionarlo. –
El _ * podría * técnicamente estar bien. Las reglas son algo así como "Double leading _ OR leading _ seguido de mayúsculas está reservado para la implementación. Leading _ seguido de cualquier otra cosa está reservado en el espacio de nombres global".Más fácil de evitar simplemente que conduce _ es del todo;) – jalf