Tutorial :Pointer to member functions - C++ std::list sort



Question:

How do i pass a pointer to a member function to std::list.sort()?

Is this possible? Thanks

struct Node {         uint32_t ID;         char *   Value;  };    class myClass {            private:              uint32_t  myValueLength;            public:              list<queueNode *> MyQueue;              bool compare(Node * first, Node * second);              bool doStuff();  }    bool myClass::compare(Node * first, Node * second) {      unsigned int ii =0;      while (ii < myValueLength)      {          if (first-> Value[ii] < second-> Value[ii])           {              return true;          } else if (first-> Value[ii] > second-> Value[ii])          {              return false;          }            ++ii;      }        return false;  }    bool myClass::doStuff()  {      list.sort(compare);  }  

I want to use a length variable from within the class instead of doing strlen() within the compare function (The Value will always be the same length)

Edit: The myValueLength was not the only variable i wanted to access from within the comparison function I just simplified it to make the example shorter.


Solution:1

Elaborating on grieve's response, why not use a functor? E.g.:

struct Functor  {    bool operator()( char * a, char * b )      { return strcmp(a,b) < 0; }  };  

Then you could just use:

Functor f;  myList.sort(f);  

You could even use your class as the Functor by defining operator()...

class myClass {    ...    bool operator()( queueNode * a, queueNode * b )    { return compare( a, b ); }      void doStuff() { MyQueue.sort(*this); }  };  

Simple example code:

#include <iostream>  #include <list>  using namespace std;      // Assumes  TYPE t; cout << t;  is valid.  template<class TYPE>  inline ostream & operator<< ( ostream & theOstream,                                const list<TYPE> & theList )  {    typename list<TYPE>::const_iterator listIterator = theList.begin();    for ( int i = 0;   listIterator != theList.end();  listIterator ++, i ++ )      theOstream << "    [" << i << "]:   \"" << (*listIterator) << "\"" << endl;    return theOstream;  }    struct Functor  {    bool operator()( const char * a, const char * b )      { return strcmp(a,b) < 0; }  };    int  main()  {    list<char*>  l;        /* Load up some example test data... */    char  s[3];    s[2] = '\0';    for (   s[0]='c'; s[0]>='a'; s[0]-- )      for ( s[1]='c'; s[1]>='a'; s[1]--  )        l.push_back(strdup(s));        /* Show us that test data... */    cout << l << endl;        /* Sort list. */    Functor f;    l.sort(f);        /* Show us what we have now... */    cout << l << endl;  }  


Solution:2

It is possible. Did you consider using boost::function?

list.sort( boost::bind( &myClass::compare, this, _1, _2 ) );  

Is your 'compare' function will rely on this data? If not - you may simpy make 'compare' function to be static. And then it will be

list.sort( &myClass::compare );  

You can add helper struct to do your comparison and then

list.sort( Comparer( myValueLength ) );    struct Comparer  {      Comparer( uint32_t myValueLength ):          length( myValueLength )      {}        bool operator() (Node * first, Node * second)      {          unsigned int ii =0;          while (ii < length)          {              if (first-> Value[ii] < second-> Value[ii])               {                      return true;              } else if (first-> Value[ii] > second-> Value[ii])              {                      return false;              }                ++ii;          }            return false;      }          uint32_t length;  };  


Solution:3

You may want to use a functor.

http://www.newty.de/fpt/functor.html


Solution:4

Note that std::list sorts the element according to operator< defined for that element. You need to change your compare function to use a global operator< defined for Node objects:

bool operator<(Node const& first, Node const& second) {  unsigned int ii =0;  while (ii < length)  {      if (first.Value[ii] < second.Value[ii])       {              return true;      } else if (first.Value[ii] > second.Value[ii])      {              return false;      }        ++ii;   }    return false;  

}

A suggested improvement will be:

bool operator<(Node const& first, Node const& second) {      for (size_t ii =0; first.Value[ii] == second.Value[ii]; ++ii) ; // note ;      return (first.Value[ii] < second.Value[ii]);  }  

If char *Value really represents a C-style string, and you want lexicographic sorting, further improvements are possible:

bool operator<(Node const& first, Node const& second) {       return (strcmp(first.Value, second.Value) < 0);  }  

and if they are really strings, I suggest you use std::string and you can write:

bool operator<(Node const& first, Node const& second) {       return first.Value < second.Value;  }  


Solution:5

As grieve & mrree suggested

simply overloading the () operator works

Thanks everyone who answered

struct Node {         uint32_t ID;         char     *       Value;  };    class myClass {            private:              uint32_t  myValueLength;            public:              list<queueNode *> MyQueue;              bool operator()(Node * first, Node * second);              bool doStuff();  }    bool myClass::operator()(Node * first, Node * second) {      unsigned int ii =0;      while (ii < myValueLength)      {          if (first-> Value[ii] < second-> Value[ii])           {                  return true;          } else if (first-> Value[ii] > second-> Value[ii])          {                  return false;          }            ++ii;      }        return false;  }    bool myClass::doStuff()  {      list.sort(*this);  }  


Solution:6

Why not make your compare function static then you no longer need the functor. Then you can simply do list.sort(compare);

nevermind ... i just realized your compare function is using a class data member so it cannot be static. Use Functor :)


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »