2008-11-30 6 views
11

Vielen Dank für ein solution in C, jetzt würde Ich mag diese in C++ erreichen mit std :: sort und Vektor:Wie std :: sort mit einem Vektor von Strukturen zu verwenden und Funktion zu vergleichen?

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

vector<pkt> wektor; gefüllt push_back mit(); Vergleichsfunktion:

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 < pkt_b->alfa) return -1; 

    if (pkt_a->x > pkt_b->x) return 1; 
    if (pkt_a->x < pkt_b->x) return -1; 

    return 0; 
} 

sort(wektor.begin(), wektor.end(), porownaj); // this makes loads of errors on compile time 

Was ist zu korrigieren? Wie benutzt man richtig std :: in diesem Fall?

Antwort

25

std::sort nimmt eine andere Vergleichsfunktion als in qsort. Anstatt -1, 0 oder 1 zurückzugeben, wird erwartet, dass diese Funktion einen bool Wert zurückgibt, der angibt, ob das erste Element kleiner als das zweite ist.

Sie haben zwei Möglichkeiten: Implementieren Sie operator < für Ihre Objekte; In diesem Fall wird der Standardaufruf sort ohne ein drittes Argument funktionieren. oder Sie können Ihre obige Funktion neu schreiben, um dasselbe zu erreichen.

Beachten Sie, dass Sie starke Argumente in den Argumenten verwenden müssen.

Außerdem ist es gut, hier überhaupt keine Funktion zu verwenden. Verwenden Sie stattdessen ein Funktionsobjekt. Diese profitieren von Inlining.

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 (a.x < b.x) return true; 
     if (a.x > b.x) return false; 

     return false; 
    } 
}; 

// Usage: 

sort(wektor.begin(), wektor.end(), pkt_less()); 
+1

Sie haben nicht einmal einen Funktor verwenden müssen. Warum nicht einfach eine normale Funktion verwenden, es sind weniger Zeilen Code? –

+2

Dave, der Grund ist, dass Funktoren inline sein können, da der Funktortyp dem Compiler sagt, welche Funktion zur Kompilierzeit aufgerufen wird. Mit Funktionszeigern kennt der Compiler dies nur zur Laufzeit und kann nicht inline. –

+0

@ onebyone.livejournal.com: Nicht wahr. Ein Funktionszeiger kann NICHT inline sein. Der Compiler darf diese Optimierung nicht durchführen. (Obwohl ein Zeiger ein Funktor ist). –

7

In C++ können Sie functors wie boost::bind die schön diesen Job verwenden:

#include <vector> 
#include <algorithm> 

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

Wenn Sie dies viele Male tun müssen, können Sie auch das Problem lösen, indem ein Funktionsobjekt machen die akzeptiert Mitgliedszeiger und führt die Sortierung durch. Sie können es für alle Arten von Objekten und Mitgliedern wiederverwenden. Zuerst wie Sie es verwenden:

int main() { 
    /* sorting a vector of pkt */ 
    std::vector<pkt> 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)); 
} 

Hier ist der Code für make_cmp. Fühlen Sie sich frei, es zu zerreißen (mit boost::preprocessor):

#include <boost/preprocessor/repetition.hpp> 
#include <boost/preprocessor/facilities/empty.hpp> 

// 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 <typename T            \ 
       BOOST_PP_ENUM_TRAILING_PARAMS(n, typename M)>    \ 
    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<typename T             \ 
      BOOST_PP_ENUM_TRAILING_PARAMS(n, typename M)>    \ 
    cmp##n<T BOOST_PP_ENUM_TRAILING_PARAMS(n, M)>      \ 
     make_cmp(BOOST_PP_ENUM(n, PARAM_print, ~))      \ 
    {                 \ 
     return cmp##n<T BOOST_PP_ENUM_TRAILING_PARAMS(n, M)>(   \ 
      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 
5

Mit C++ 0x und lambdas Konrad-Lösung sieht wie folgt aus:

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 (a.x < b.x) return true; 
    if (a.x > b.x) return false; 

    return false; 
}); 
Verwandte Themen