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

Сорт:

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++ для list::sort

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

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

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

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


person encore2097    schedule 04.12.2011    source источник
comment
Пожалуйста, не используйте все идентификаторы в верхнем регистре (кроме макросов, где вы должны их использовать).   -  person Cheers and hth. - Alf    schedule 04.12.2011
comment
Фиксированный. Пытался выделить соответствующую информацию.   -  person encore2097    schedule 04.12.2011
comment
Это С++11? Можете ли вы использовать лямбды или bind()?   -  person Kerrek SB    schedule 04.12.2011
comment
¤ Основная идея состоит в том, чтобы передать объект с operator(), чтобы его можно было использовать как функцию. Это называется функтор. В C++11 можно на лету создать такого зверя, как лямбду. В C++98/03 вам нужно либо определить для него класс, либо использовать стороннюю библиотеку, например Boost. Например. вы можете использовать boost::bind, чтобы получить указатель на ваш words, переданный вашей реальной функции. Ура и чт.,   -  person Cheers and hth. - Alf    schedule 04.12.2011


Ответы (2)


Ответ @Kerrek с лямбда-выражениями лучше. Но если вы должны избегать функций С++ 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();
}
person Robᵩ    schedule 04.12.2011
comment
Не могу превзойти классность лямбда-выражений, но для этого требуется С++ 11, который я в настоящее время не могу использовать. - person encore2097; 04.12.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));
}
person Kerrek SB    schedule 04.12.2011
comment
@kol: Вы должны сами расшифровать предикат. Каждая лямбда может быть тривиально расширена до функтора; это просто шумно. Вам нужна помощь с этим? - person Kerrek SB; 04.12.2011
comment
Хм... Я получаю следующие ошибки при попытке метода привязки (Ubuntu linux x64, g++ v.4.4.3 :) error: ‘placeholders’ is not a namespace-name error: expected namespace-name before ‘;’ token error: ‘bind’ is not a member of ‘std’ error: ‘_1’ was not declared in this scope error: ‘_2’ was not declared in this scope - person encore2097; 04.12.2011
comment
@Kerrek SB: Спасибо, забыл указать стандарт. @ Роб: Я не уверен, что вы имеете в виду. - person encore2097; 04.12.2011