简体   繁体   中英

C++ std::sort with predicate function in Class

I want to sort vector of certain struct with certain order in certain class. I've wrote definition of struct and predicate function in a class and run std::sort in a method of the class with these struct and function. But compilation error has occurred. gcc version is 4.0.1 and OS is Mac OSX. The code is following:

class sample {
public:
  struct s {
    int x;
    int y;
  };

  bool cmp (struct s a, struct s b) {
    if (a.x == b.x)
      return a.y < b.y;
    else
      return a.x < b.x;
  }

  int func(void) {
    std::vector <struct s> vec;

    // ...

    sort(vec.begin(), vec.end(), cmp);  // compilation error

    // ...

    return 0;
  }
};

int main(void) {
  sample *smp = new sample();
  smp->func();
  return 0;
}

Error message was huge and complex. So this is first two lines of it.

sortSample.cpp: In member function 'int sample::func()':
sortSample.cpp:51: error: argument of type 'bool (sample::)(sample::s, sample::s)' does not match 'bool (sample::*)(sample::s, sample::s)'
...

Instead of above approach, the code could run correctly with following ways.

  1. Define struct s and function cmp() outside of class sample .
  2. Remove function cmp() and define operator overloading of < in struct s .

Sample code of each approach is bellow.

1)

struct s {
  int x;
  int y;
};

bool cmp (struct s a, struct s b) {
  if (a.x == b.x)
    return a.y < b.y;
  else
    return a.x < b.x;
}

class sample {
// ...

2)

struct s {
  int x;
  int y;

  bool operator<(const struct s & a) const {
    if (x == a.x)
      return y < a.y;
    else
      return x < a.x;
  }
};

Can anyone tell a mechanism of this behavior? Why does first approach invokes compilation error?

Thanks.

In the first case cmp is declared as a member function of the class sample and hence requires this pointer for calling it. Since the this pointer is not available compiler is complaining about it. You can make it work by declaring cmp as static function since static functions do not require this pointer for calling. In the second case, since cmp is declared as a stand-alone function again it will behave same as static function. In the third case (with overloaded operator), the sort algorithm will take care of calling the function for each object in the vector and hence it compiles.

由于cmp与任何特定的样本实例无关,因此将其设为静态成员函数。

The third approach which can be listed in your possibilities is using operator():

bool operator() (const s& a, const s& b) const
{
    if (a.x == b.x)
        return a.y < b.y;
    else
        return a.x < b.x;
}

sort(vec.begin(), vec.end(), *this);

I think defining cmp outside the class is best, because you should only make a function a member function when you need it to access some private feature in the class, and logically it feels right for it to be there. cmp is just a utility function that provides your class sample with functionality for its implementation, but it doesn't actually need to access private members. Furthermore, it's probably not going to be invoked in the context of an object (its only operations work on its parameters; nothing on the this pointer), nor must it be invoked in the context of a class sample::cmp . While it may seem like a trivial point, giving functions or code in general unnecessary breadth of access can be the start of the source of many a software bug or design convolution.

The added benefit of doing the above is that your invocation of std::sort will work, which answers your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM