C ++ стандартный список сортировки с пользовательским компаратором, который зависит от переменной-члена для экземпляра объекта - PullRequest
4 голосов
/ 04 декабря 2011

Класс:

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

Я вызываю сортировку по непустому списку в другой функции-члене:

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

Моя функция сортировки:

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

Ошибка:

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>]

Я исследовал и столкнулся со следующими вопросами:

C ++ Пользовательская функция сравнения для списка :: sort

Проблема с сортировкой списка указателей

Ошибка в std :: list :: sort с пользовательским компаратором (ожидаемое первичное выражение до маркера ')')

и их было бы достаточно, если бы не тот факт, что в этом классе sortFunc зависит от переменной-члена WORDS для этого экземпляра объекта. Поэтому я не могу сделать функцию компаратора (sortFunc) статической или глобальной

РЕДАКТИРОВАТЬ: Только что натолкнулся на это Как отсортировать список std: когда вам нужны данные члена? и он предоставляет решение путем создания класса друга, но возможно ли это сделать внутри пользователя? определил сам класс?

Ответы [ 3 ]

9 голосов
/ 04 декабря 2011

С лямбдами:

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

С std::bind:

#include <functional>

//...
{
  using namespace std::placeholders;
  vints[i].sort(std::bind(&myClass::sortFunc, this, _1, _2));
}
2 голосов
/ 04 декабря 2011

@ Ответ Керрека с лямбдами лучше. Но если вам нужно избегать функций C ++ 11, замените функцию сортировки на функтор. Разрешить этому функтору хранить ссылку на любые необходимые данные, например:

#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();
}
0 голосов
/ 04 декабря 2011

=== ОБНОВЛЕНО ===

Вот обходной путь без использования функций C ++ 11:

#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;
}

Я пропустил проверку диапазона радипростотыВыход:

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