[C++] STL sort

hamming_burst
Salve,
chiede un piccolo aiuto nel capire come risolvere un problema con la fun delle STL del C++, sort().
Quello che voglio fare è utilizzare la versione di sort, dove è possibile passare una propria definizione di compare.

void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );


Le classi in generale sono fatte in questo modo:

class Ess{

public :
	unsigned char va;
};


class EssList : public std::vector<Ess>{

private:

	bool function_sort(Ess l1, Ess l2);

public :
	/*other*/

	void sorting(void);

};

bool EssList::function_sort(Ess l1, Ess l2){

	/*modify other*/

return (l1.va<l2.va);

}

void EssList::sorting(void){

	sort(this->begin(),this->end(),function_sort);

}

int main(){

	EssList list;
	list.sorting();

}


ora compilando il problema è la definizione di
function_sort()
. Come diamine si gestisce il caso che nel vettore ci siano tipi complessi come una classe e non semplici interi, come vanno passati: riferimento, valore, ...
(non posso riportare l'output del compilatore)

ho visto che si possono fare altre versioni di sort() utilizzando come compare un operator, ma non va bene nel mio caso.

Ringrazio chi aiuta :-)

Risposte
claudio862
Il problema è che la funzione function_sort() (che dovrebbe chiamarsi function_compare()) è una funzione membro mentre std::sort() si aspetta una funzione libera. Puoi dichiararla come funzione membro statica.
Per tipi non primitivi di solito si passano riferimenti costanti:

#include <vector>
#include <algorithm>

class Ess{
public :
   unsigned char va;
};

class EssList : public std::vector<Ess>{

private:

   static bool function_sort(const Ess & l1, const Ess & l2);

public :
   /*other*/

   void sorting(void);

};

bool EssList::function_sort(const Ess & l1, const Ess & l2){

   /*modify other*/

return (l1.va<l2.va);

}

void EssList::sorting(void){
   sort(this->begin(),this->end(),function_sort);
}

int main(){

   EssList list;
   list.sorting();

}


Altrimenti definisci l'operatore < nella classe Ess:

class Ess{
public :
    unsigned char va;
    bool operator<(const Ess & other) const
    {
        return va < other.va;
    }
};


Oppure come funzione libera:

bool operator<(const Ess & a, const Ess & b)
{
    return a.va < b.va;
}


Un'ultima nota: i contenitori standard (std::vector, std::list...) non hanno il distruttore virtuale, quindi non è quasi mai una buona idea ereditare da essi (anche se nel tuo caso non ci sono variabili di classe in EssList quindi potrebbe anche andare). Se l'unica utilità della classe EssList (meglio EssVector oltretutto) è quella di offrire una funzione sorting() faresti meglio a lasciare perdere.

apatriarca
Condivido l'opinione di claudio86 nella sua ultima nota. E' in generale una cattiva idea ereditare dai contenitori standard. Inoltre le funzioni libere sono in generale quelle che offrono una maggiore libertà di utilizzo e sono spesso preferibili alle alternative. In effetti, Scott Meyers, più di 10 anni fa ma le cose sono cambiate ancora più a favore delle funzioni libere, ha scritto ad esempio un articolo descrivendo i vantaggi a livello di incapsulamento derivanti dall'uso di funzioni non-membro (qui). Molte funzioni delle librerie standard (la maggior parte di quelle contenute in algorithms per esempio) prediligono le funzioni libere anche se esistono funzioni template (standard o in boost) e le funzioni lambda di boost (e adesso C++11) per ridurre tali difficoltà.

hamming_burst
Per il momento per far girare il codice ho messo una pezza in questo modo:

class Ess{

public :
   unsigned char va;
};

class EssList : public std::vector<Ess>{

public :
   /*other*/

};


class CompareSort {
public :
         bool operator()(const Ess& l1, const Ess& l2) const{
               return (l1.va < l2.va);
         }
}


void sorting(EssList& list){

      /*modify other*/
    CompareSort cmp;
    std::sort(this->begin(),this->end(),cmp);

}


in pratica ho estrapolato la funzione dalla mia classe, anche se non è molto elegante così funzia. La classe è abb complessa e serve per aggiunge delle funzionalità al vector. Ma utilizzo direttamente le funzioni ereditate senza sovrascriverle.

Detto questo, vi ringrazio delle risposte e pareri. Lunedì vedo come sistemare il tutto.

Per quanto riguarda l'ereditarietà allora cosa consigliate? Meglio strutture membro ed una classe generale che le racchiude?
L'articolo sembra interessante e mi sa che devo iniziare a ragionare in altro modo. Di solito in Java, cerco di ridurmi quasi sempre a modelli Delegation o classica Inheritance.

apatriarca
Che genere di funzionalità aggiuntive vorresti aggiungere? Sei certo che non sarebbe più semplice definire semplicemente delle funzioni libere che lavorano su dei vector (o ancora meglio su iteratori)? Qualcosa di simile alle funzioni in algorithms. Sei certo che tali funzionalità non ci siano già da qualche parte all'interno di boost o std?

hamming_burst
"apatriarca":
Che genere di funzionalità aggiuntive vorresti aggiungere?

le ho già aggiunte :-)
Cmq diciamo che in aggiunta ci sono alcuni stream (fstream, QStreamData, ...), qualche stuttura di controllo, sono distribuiti a seconda dell'utilità, non sono tutti inglobati nella classe che qui ho chiamato EssList.

In pratica la cosa importante è il vettore (o mappa in altri casi), le cose in più servono per averne accesso direttamente.

Sei certo che non sarebbe più semplice definire semplicemente delle funzioni libere che lavorano su dei vector (o ancora meglio su iteratori)?

purtroppo i vector sono specializzati non sono in tamplate perchè non ha senso che sia così.


Qualcosa di simile alle funzioni in algorithms. Sei certo che tali funzionalità non ci siano già da qualche parte all'interno di boost o std?

certo, lavoro con alcune librerie interne e tali funzionalità non ci sono.

apatriarca
E' ovviamente difficile giudicare delle scelte di progettazione senza avere idea di che cosa si tratti. Credo che l'utilizzo di funzioni libere sia in generale preferibile in C++ quando si vogliano aggiungere funzionalità che facciano solo uso dell'interfaccia pubblica di una qualche classe. Una funzione che aggiunga funzionalità a vector non deve comunque essere per forza template. Ma ormai immagino che non valga la pena di cambiare tutto per cui se ne parlerà per il prossimo progetto o situazione simile.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.