¿Cómo usar std :: sort con un vector de estructuras y comparar función?

Gracias por una solución en C , ahora me gustaría lograr esto en C ++ usando std :: sort y vector:

typedef struct { double x; double y; double alfa; } pkt; 

vector wektor; lleno usando push_back (); función de comparación:

 int porownaj(const void *p_a, const void *p_b) { pkt *pkt_a = (pkt *) p_a; pkt *pkt_b = (pkt *) p_b; if (pkt_a->alfa > pkt_b->alfa) return 1; if (pkt_a->alfa alfa) return -1; if (pkt_a->x > pkt_b->x) return 1; if (pkt_a->x x) return -1; return 0; } sort(wektor.begin(), wektor.end(), porownaj); // this makes loads of errors on compile time 

¿Qué es corregir? Cómo usar correctamente std :: sort en ese caso?

std::sort toma una función de comparación diferente de la utilizada en qsort . En lugar de devolver -1, 0 o 1, se espera que esta función devuelva un valor bool que indica si el primer elemento es menor que el segundo.

Usted tiene dos posibilidades: implementar operator < para sus objetos; en ese caso, la invocación de sort predeterminada sin un tercer argumento funcionará; o puede reescribir su función anterior para lograr lo mismo.

Tenga en cuenta que debe usar una escritura fuerte en los argumentos.

Además, es bueno no usar ninguna función aquí. En cambio, use un objeto de función. Estos se benefician de la creación de líneas.

 struct pkt_less { bool operator ()(pkt const& a, pkt const& b) const { if (a.alfa < b.alfa) return true; if (a.alfa > b.alfa) return false; if (ax < bx) return true; if (ax > bx) return false; return false; } }; // Usage: sort(wektor.begin(), wektor.end(), pkt_less()); 

En C ++, puedes usar funtores como boost::bind que hacen bien este trabajo:

 #include  #include  struct pkt { double x; double y; double alfa; pkt(double x, double y, double alfa) :x(x), y(y), alfa(alfa) { } }; int main() { std::vector p; p.push_back(pkt(10., 0., 20.)); p.push_back(pkt(10, 0., 30.)); p.push_back(pkt(5., 0., 40.)); std::sort(p.begin(), p.end(), boost::bind(&pkt::alfa, _1) < boost::bind(&pkt::alfa, _2) || boost::bind(&pkt::alfa, _1) == boost::bind(&pkt::alfa, _2) && boost::bind(&pkt::x, _1) < boost::bind(&pkt::x, _2)); } 

Si necesita hacer esto muchas veces, también puede resolver el problema haciendo un objeto de función que acepte punteros de miembro y haga el ordenamiento. Puede reutilizarlo para cualquier tipo de objeto y miembros. Primero cómo lo usa:

 int main() { /* sorting a vector of pkt */ std::vector p; p.push_back(pkt(10., 0., 20.)); p.push_back(pkt(5., 0., 40.)); std::sort(p.begin(), p.end(), make_cmp(&pkt::x, &pkt::y)); } 

Aquí está el código para make_cmp. Siéntete libre de ripearlo (usando boost::preprocessor ):

 #include  #include  // tweak this to increase the maximal field count #define CMP_MAX 10 #define TYPEDEF_print(z, n, unused) typedef M##n T::* m##n##_type; #define MEMBER_print(z, n, unused) m##n##_type m##n; #define CTORPARAMS_print(z, n, unused) m##n##_type m##n #define CTORINIT_print(z, n, unused) m##n(m##n) #define CMPIF_print(z, n, unused) \ if ((t0.*m##n) < (t1.*m##n)) return true; \ if ((t0.*m##n) > (t1.*m##n)) return false; \ #define PARAM_print(z, n, unused) M##n T::* m##n #define CMP_functor(z, n, unused) \ template  \ struct cmp##n { \ BOOST_PP_REPEAT(n, TYPEDEF_print, ~) \ BOOST_PP_REPEAT(n, MEMBER_print, ~) \ cmp##n(BOOST_PP_ENUM(n, CTORPARAMS_print, ~)) \ BOOST_PP_IF(n, :, BOOST_PP_EMPTY()) \ BOOST_PP_ENUM(n, CTORINIT_print, ~) { } \ \ bool operator()(T const& t0, T const& t1) const { \ BOOST_PP_REPEAT(n, CMPIF_print, ~) \ return false; \ } \ }; \ \ template \ cmp##n \ make_cmp(BOOST_PP_ENUM(n, PARAM_print, ~)) \ { \ return cmp##n( \ BOOST_PP_ENUM_PARAMS(n, m)); \ } BOOST_PP_REPEAT(CMP_MAX, CMP_functor, ~) #undef TYPEDEF_print #undef MEMBER_print #undef CTORPARAMS_print #undef CTORINIT_print #undef CMPIF_print #undef PARAM_print #undef CMP_functor 

Con C ++ 0x y lambdas, la solución de Konrad se ve así:

 sort(wektor.begin(), wektor.end(), [](pkt const& a, pkt const& b) { if (a.alfa < b.alfa) return true; if (a.alfa > b.alfa) return false; if (ax < bx) return true; if (ax > bx) return false; return false; });