ordinamento problema utilizzando la funzione membro come comparatore

cercando di compilare il codice seguente ottengo questo errore di compilazione, cosa posso fare?


ISO C ++ proibisce di prendere l’indirizzo di una funzione membro non statico non classificato o tra parentesi per formare un puntatore alla funzione membro.

class MyClass { int * arr; // other member variables MyClass() { arr = new int[someSize]; } doCompare( const int & i1, const int & i2 ) { // use some member variables } doSort() { std::sort(arr,arr+someSize, &doCompare); } }; 

doCompare deve essere static . Se doCompare bisogno di dati da MyClass puoi trasformare MyClass in un functor di confronto cambiando:

 doCompare( const int & i1, const int & i2 ) { // use some member variables } 

in

 bool operator () ( const int & i1, const int & i2 ) { // use some member variables } 

e chiamando:

 doSort() { std::sort(arr,arr+someSize, *this); } 

Inoltre, non manca doSort un valore di ritorno?

Penso che dovrebbe essere ansible usare std::mem_fun e una sorta di associazione per trasformare la funzione membro in una funzione libera, ma la syntax esatta mi sfugge al momento.

EDIT: Doh, std::sort prende il functor in base al valore che potrebbe essere un problema. Per aggirare questo avvolgere il functor all’interno della class:

 class MyClass { struct Less { Less(const MyClass& c) : myClass(c) {} bool operator () ( const int & i1, const int & i2 ) {// use 'myClass'} MyClass& myClass; }; doSort() { std::sort(arr,arr+someSize, Less(*this)); } } 

Come dice Andreas Brinck, doCompare deve essere statico (+1). Se si deve avere uno stato nella funzione di confronto (usando gli altri membri della class), è meglio usare un functor invece di una funzione (e che sarà più veloce):

 class MyClass{ // ... struct doCompare { doCompare( const MyClass& info ) : m_info(info) { } // only if you really need the object state const MyClass& m_info; bool operator()( const int & i1, const int & i2 ) { // comparison code using m_info } }; doSort() { std::sort( arr, arr+someSize, doCompare(*this) ); } }; 

L’utilizzo di un functor è sempre migliore, solo più lungo da digitare (che può essere scomodo ma vabbè …)

Penso che si possa usare anche std :: bind con la funzione membro, ma non sono sicuro di come e non sarebbe facile leggere comunque.

AGGIORNAMENTO 2014: Oggi abbiamo accesso ai compilatori c ++ 11 in modo da poter utilizzare invece una lambda, il codice sarebbe più breve ma avere la stessa identica semantica.

La soluzione proposta da Rob è ora valida C ++ 11 (non c’è bisogno di Boost):

 void doSort() { using namespace std::placeholders; std::sort(arr, arr+someSize, std::bind(&MyClass::doCompare, this, _1, _2)); } 

Infatti, come accennato da Klaim, lambda è un’opzione, un po ‘più prolissa (devi “ripetere” che gli argomenti sono inti):

 void doSort() { std::sort(arr, arr+someSize, [this](int l, int r) {return doCompare(l, r); }); } 

C ++ 14 supporta l’ auto qui:

 void doSort() { std::sort(arr, arr+someSize, [this](auto l, auto r) {return doCompare(l, r); }); } 

ma ancora, hai dichiarato che gli argomenti sono passati per copia.

Quindi la domanda è “quale è il più efficiente”. La domanda è stata trattata da Travis Gockel: Lambda vs Bind . Il suo programma di riferimento dà sul mio computer (OS X i7)

  Clang 3.5 GCC 4.9 lambda 1001 7000 bind 3716166405 2530142000 bound lambda 2438421993 1700834000 boost bind 2925777511 2529615000 boost bound lambda 2420710412 1683458000 

dove lambda è un lambda usato direttamente, e lambda bound è un lambda memorizzato in una std::function .

Quindi sembra che i lambda siano un’opzione migliore, il che non è troppo sorprendente dato che il compilatore è dotato di informazioni di livello superiore da cui può trarre profitto.

Puoi usare boost::bind :

 void doSort() { std::sort(arr,arr+someSize, boost::bind(&MyClass::doCompare, this, _1, _2)); } 

C’è un modo per fare ciò che vuoi, ma devi usare un piccolo adattatore. Come STL non lo scrive per te, puoi scriverlo tu stesso:

 template  struct adaptor_t { typedef bool (Base::*method_t)(const T& t1, const T& t2)); adaptor_t(Base* b, method_t m) : base(b), method(m) {} adaptor_t(const adaptor_t& copy) : base(copy.base), method(copy.method) {} bool operator()(const T& t1, const T& t2) const { return (base->*method)(t1, t2); } Base *base; method_t method; } template  adaptor_t adapt_method(Base* b, typename adaptor_t::method_t m) { return adaptor_t(b,m); } 

Quindi, puoi usarlo:

 doSort() { std::sort(arr,arr+someSize, adapt_method(this, &doCompare)); } 

Un modo molto semplice per utilizzare efficacemente una funzione membro è utilizzare l’operatore <. Cioè, se hai una funzione chiamata compare, puoi chiamarla dall'operatore <. Ecco un esempio funzionante:

 class Qaz { public: Qaz(int aX): x(aX) { } bool operator<(const Qaz& aOther) const { return compare(*this,aOther); } static bool compare(const Qaz& aP,const Qaz& aQ) { return aP.x < aQ.x; } int x; }; 

Quindi non è nemmeno necessario assegnare il nome della funzione a std :: sort:

 std::vector q; q.emplace_back(8); q.emplace_back(1); q.emplace_back(4); q.emplace_back(7); q.emplace_back(6); q.emplace_back(0); q.emplace_back(3); std::sort(q.begin(),q.end()); 

Aggiornare la risposta di Graham Asher, poiché non è necessario il confronto, ma è ansible utilizzare meno operatori direttamente.

 #include  #include  #include  using namespace std; class Qaz { public: Qaz(int aX): x(aX) { } bool operator<(const Qaz& aOther) const { return x < aOther.x; } int x; }; int main() { std::vector q; q.emplace_back(8); q.emplace_back(1); q.emplace_back(4); q.emplace_back(7); q.emplace_back(6); q.emplace_back(0); q.emplace_back(3); std::sort(q.begin(),q.end()); for (auto& num : q) std::cout << num.x << "\n"; char c; std::cin >> c; return 0; }