C++ - std::sort with a non-static compare method

Usually when you want to sort a std::vector or another container thats holds objects of a custom datatype, you just write a compare function that takes two such objects, does something to find out if one is less than the other, and returns true if it is. Then you pass the address of this function to std::sort and voila.

But what when you want to make your sort function take some non-global data into account?
Usually such data, for example a boolean value deciding to sort in ascending or descending order, will be a member of the same class your vector is in. Now the obvious solution would be to simply put the compare function inside that class, and have it use the data.
Unfortunately though, we cannot call std::sort with a member-function pointer.
But, instead of a function pointer, std::sort also accepts a typename, or an object of a type, that defines operator().
So, to solve our problem, we can simply define a private member class or struct, that overloads operator(), and where the implementation of operator() resembles a compare function (it takes two arguments and returns true if the first argument is smaller than the second). This class/struct has access to the data our sort depends on, and can be passed as an argument to std::sort, which will then use its operator().

Here is a small sample program showing this in action:
#include <vector>
#include <algorithm>
#include <iostream>
 
using namespace::std;
 
class myclass
{ 
 bool sortascending; // this is the data our sort depends on
 vector<int> vec;
 
 struct sortstruct
 {
  // sortstruct needs to know its containing object
  myclass* m;
  sortstruct(myclass* p) : m(p) {};
 
  // this is our sort function, which makes use
  // of some non-static data (sortascending)
  bool operator() ( int i, int j )
  {
   if ( m->sortascending )
    return i < j;
   else return i > j;
  }
 };
 
public:
 myclass ( bool b ) : sortascending(b) {}
 
 void init  ()
 { // just some values for testing
  vec.push_back(3); vec.push_back(100); 
  vec.push_back(10); vec.push_back(143);
 }
 void sort  ()
 {
  // create a sortstruct and pass it to std::sort
  sortstruct s(this);
  std::sort ( vec.begin (), vec.end (), s );
 }
 void print ()
 { // print the vector values to the console
  for (int i = 0; i < vec.size(); i++)
   std::cout << vec[i] << std::endl;
 }
};
 
void main()
{
 myclass m(true);
 m.init();
 m.sort();
 m.print();
}

No comments:

Post a Comment