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?
std::sort
takes a different compare function from that used in qsort
bool
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());
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
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; });