C++ std list sort with custom comparator that depends on an member variable for the object instance

独自空忆成欢 提交于 2019-12-19 08:50:15

问题


Class:

Class:
  private:
    ...
    vector<string> words; 
    vector< list<int> > vints;
  public:
    myFunction(...)

I am calling a sort on non-empty list in another member function:

void myClass::myFunction (...) {
    ...
    if (!vints[i].empty()) vints[i].sort(sortFunc);
    ...
}

My sorting function:

bool myClass::sortFunc(const int& i, const int& j) { return (words[i] < words[j]); }

The Error:

error: no matching function for call to ‘std::list<int, std::allocator<int>      >::sort(<unresolved overloaded function type>)’
/usr/include/c++/4.4/bits/list.tcc:301: note: candidates are: void std::list<_Tp,     _Alloc>::sort() [with _Tp = int, _Alloc = std::allocator<int>]
/usr/include/c++/4.4/bits/list.tcc:378: note:                 void std::list<_Tp, _    Alloc>::sort(_StrictWeakOrdering) [with _StrictWeakOrdering = bool (SuperWordSearch::*)    (const int&, const int&), _Tp = int, _Alloc = std::allocator<int>]

I have researched and come across the following questions:

C++ Custom compare function for list::sort

Problem sorting a list of pointers

Error in std::list::sort with custom comparator (expected primary-expression before ')' token)

and they would have been sufficient had it not been for the fact that in this class, the sortFunc depends on the member variable WORDS for that instance of the object. So I cannot make the comparator function (sortFunc) static or global

EDIT: Just came across this How to sort a std:list when you need member data? and it provides a solution by making a friend class, but is it possible to accomplish this inside the user-defined class itself?


回答1:


@Kerrek's answer involving lambdas is better. But, if you must avoid C++11 features, then replace your sort function with a functor. Allow that functor to store a reference to whatever data is required, as so:

#include <vector>
#include <list>
#include <string>

class myClass {
private:
  std::vector<std::string> words;
  std::vector<std::list<int> > vints;

  // Instead of sortFunc, use sortFunctor. A functor can be used in place 
  // of a function in many places, and it can carry state (like a reference
  // to the data it needs).
  struct sortFunctor {
    const std::vector<std::string>& words;
    sortFunctor(const std::vector<std::string>& words) : words(words) { }
    bool operator()(int i, int j) { return words[i] < words[j]; }
  };

public:
  void myFunction() {
    vints[0].sort(sortFunctor(words));
  }
  myClass() {
    words.push_back("apple");
    words.push_back("berry");
    std::list<int> l;
    l.push_back(0);
    l.push_back(1);
    vints.push_back(l);
  }
};

int main () {
  myClass object;
  object.myFunction();
}



回答2:


With lambdas:

vints[i].sort([&words](int i, int j) { return words[i] < words[j]; });

With std::bind:

#include <functional>

//...
{
  using namespace std::placeholders;
  vints[i].sort(std::bind(&myClass::sortFunc, this, _1, _2));
}



回答3:


=== UPDATED ===

Here is a workaround without using C++11 features:

#include <exception>
#include <iostream>
#include <list>
#include <string>
#include <vector>

using namespace std;

class MyClass
{
private:
  vector<string*> words;
  vector< list<string*> > vptrs;
  static bool sortFunc(const string* s1, const string* s2)
  {
    return (*s1 < *s2);
  }
public:
  MyClass()
  {
    vptrs.push_back(list<string*>());
  }
  ~MyClass()
  {
    for (int i = 0; i < vptrs.size(); ++i)
      vptrs[i].clear();
    for (int i = 0; i < words.size(); ++i)
      delete words[i];
  }
  void addWord(const char* s)
  {
    words.push_back(new string(s));
  }
  void setWord(int i, const char* s)
  {
    *words[i] = s;
  }
  void addIndex(int i, int j)
  {
    vptrs[i].push_back(words.at(j));
  }
  void sort(int i)
  {
    if (!vptrs[i].empty())
      vptrs[i].sort(sortFunc);
  }
  void print(int i)
  {
    list<string*>::iterator s;
    for (s = vptrs[i].begin(); s != vptrs[i].end(); ++s)
      cout << **s << endl;
  }
};

int main(int argc, char **argv)
{
  try
  {
    MyClass* c = new MyClass();
    c->addWord("apple");
    c->addWord("hello");
    c->addWord("world");
    c->addIndex(0, 1);
    c->addIndex(0, 2);
    c->addIndex(0, 0);
    c->setWord(2, "pear");
    cout << "Before sort:" << endl;
    c->print(0);
    c->sort(0);
    cout << "After sort:" << endl;
    c->print(0);
    delete c;
  }
  catch (exception e)
  {
    cout << e.what() << endl;
  }
  getchar();
  return 0;
}

I omitted range checking for the sake of simplicity. Output:

Before sort:
hello
pear
apple
After sort:
apple
hello
pear


来源:https://stackoverflow.com/questions/8372918/c-std-list-sort-with-custom-comparator-that-depends-on-an-member-variable-for

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!