How to use std::sort with a vector of structures and compare function?

匿名 (未验证) 提交于 2019-12-03 03:05:02

问题:

Thanks for a solution in C, now I would like to achieve this in C++ using std::sort and vector:

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

vector wektor; filled up using push_back(); compare function:

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 

What is to correct? How to use properly std::sort in that case?

回答1:

std::sort takes a different compare function from that used in qsortbool value indicating whether the first element is less than the second.

You have two possibilites: implement operator for your objects; in that case, the default sort invocation without a third argument will work; or you can rewrite your above function to accomplish the same thing.

Notice that you have to use strong typing in the arguments.

Additionally, it's good not to use a function here at all. Instead, use a function object. These benefit from inlining.

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


回答2:

In C++, you can use functors like boost::bind which do this job nicely:

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

If you need to do this many times, you can also solve the problem by making a function object which accepts member pointers and does the sort. You can reuse it for any kind of object and members. First how you use it:

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

Here is the code for make_cmp. Feel free to rip it (using 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 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 


回答3:

With C++0x and lambdas Konrad's solution looks like this:

sort(wektor.begin(), wektor.end(), [](pkt const& a, pkt const& b) {     if (a.alfa  b.alfa) return false;      if (a.x  b.x) return false;      return false; }); 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!