views:

426

answers:

3

Just idly curious why the compare function for stl::sort can't be a static member?

I have a small little helper class foo that is declared and defined in a header, but now I have to create a foo.cpp file for the implementation of cmp() so it isn't multiply defined.

I also have to think of a suitably decorated name so fooCmp() doesn't clash with any other cmp().

Because it has no access to any member variables any compare operation that needs access to some other value (eg. sort by distance from foo.bar) needs the complex bind2nd call.

A: 

If you're concerned with a multiply defined compare function, try declaring the function with static linkage. Then the scope of the function does not extend past the compilation unit where it is found.

That said, your compare "function" need not be a function at all, but can instead be a function object. A function object is very much like a function but is implemented as an operator() that takes the appropriate parameters within a regular class. Since it's a regular class, you can pass constructor parameters to the class.

Here is a simple example:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class comparator {
public:
    bool operator()(int a, int b) {
        return a < b;
    }
};

int main(int, char *[])
{
    vector<int> a;
    a.push_back(1);
    a.push_back(3);
    a.push_back(2);
    sort(a.begin(), a.end(), comparator());
    cout << a << endl;
}
Greg Hewgill
+3  A: 

I am not sure what you are complaining about:

std::sort(begin,end)        // use operator<
std::sort(begin,end,order)  // Where order is a functor

So order can be:

  • A function
  • A static member function
  • Or an object that behaves like a function.

The following works for me:

class X
{
    public: static bool diff(X const& lhs,X const& rhs) { return true;}
};

int main()
{
    std::vector<X>   a;

    std::sort(a.begin(),a.end(),&X::diff);
}

But if the class has some natural ordering then why not just define the operator< for the class. This will allow you the access to the members and will behave nicely for most of the standard containers/algorithms that need to define an ordering.

class X
{
    public: bool operator<(X const& rhs) const   {  return true;}
};
int main()
{
    std::vector<X>   a;

    std::sort(a.begin(),a.end());
}
Martin York
Sorry had the defn slightly wrong - I thought I had remembered that you couldn't do this.
Martin Beckett
Richard Corden
@mgb: The example you may be thinking of is where your predicate function is itself a template. The problem there is that the predicate arguments are not automatically deduced and so you must explicitly specify them when you call std::sort.
Richard Corden
@Richard. Are you stalking me :-) I though the list above included "free function" is that not the same as "A function" as apposed to "A Method" which you can not pass to sort.
Martin York
@Martin: No I'm not stalking you (at least not intentionally)! Re my "free function" comment, hmmm - you're right I don't know now how I missed "function" in your list.
Richard Corden
A: 

actually sounds like the function was declared in the class, defined in the header but outside the class without inline linkage

ie something like:

class foo{
public:
   static bool compare(const foo& lhs,const foo& rhs);
   ...
};
bool foo::compare(const foo& lhs,const foo& rhs){
   ...
}

instead of

class foo{
public:
   static bool compare(const foo& lhs,const foo& rhs);
   ...
};
inline bool foo::compare(const foo& lhs,const foo& rhs){
   ...
}

the first of which will cause the function to be defined in every compilation unit that

#includes "foo.h"
pgast