сортировка проблем с использованием функции-члена в качестве компаратора - PullRequest
25 голосов
/ 14 декабря 2009

пытаясь скомпилировать следующий код Я получаю эту ошибку компиляции, что я могу сделать?


ISO C ++ запрещает брать адрес неквалифицированный или заключенный в скобки нестатическая функция-член для формирования указатель на функцию-член.

class MyClass {
   int * arr;
   // other member variables
   MyClass() { arr = new int[someSize]; }

   doCompare( const int & i1, const int & i2 ) { // use some member variables } 

   doSort() { std::sort(arr,arr+someSize, &doCompare); }

}; 

Ответы [ 7 ]

28 голосов
/ 14 декабря 2009

doCompare должно быть static. Если doCompare нужны данные из MyClass, вы можете превратить MyClass в функтор сравнения, изменив:

doCompare( const int & i1, const int & i2 ) { // use some member variables } 

в

bool operator () ( const int & i1, const int & i2 ) { // use some member variables } 

и звонит:

doSort() { std::sort(arr,arr+someSize, *this); }

Кроме того, doSort не пропущено возвращаемое значение?

Я думаю, что можно использовать std::mem_fun и какую-то привязку, чтобы превратить функцию-член в свободную функцию, но точный синтаксис уклоняется от меня на данный момент.

РЕДАКТИРОВАТЬ: Doh, std::sort принимает функтор по значению, что может быть проблемой. Чтобы обойти это, оберните функтор внутри класса:

class MyClass {
    struct Less {
        Less(const MyClass& c) : myClass(c) {}
        bool operator () ( const int & i1, const int & i2 ) {// use 'myClass'} 
        MyClass& myClass;
    };
    doSort() { std::sort(arr,arr+someSize, Less(*this)); }
}
13 голосов
/ 14 декабря 2009

Как говорит Андреас Бринк, doCompare должно быть статическим (+1). Если вы ДОЛЖНЫ иметь состояние в функции сравнения (используя других членов класса), то вам лучше использовать функтор вместо функции (и это будет быстрее):

class MyClass{

   // ...
   struct doCompare
   { 
       doCompare( const MyClass& info ) : m_info(info) { } // only if you really need the object state
       const MyClass& m_info;

       bool operator()( const int & i1, const int & i2  )
       { 
            // comparison code using m_info
       }
   };

    doSort() 
    { std::sort( arr, arr+someSize, doCompare(*this) ); }
};

Использование функтора всегда лучше, просто дольше печатать (это может быть неудобно, ну да ладно ...)

Я думаю, что вы также можете использовать std :: bind с функцией-членом, но я не уверен, как это будет непросто прочитать в любом случае.

ОБНОВЛЕНИЕ 2014: Сегодня у нас есть доступ к компиляторам c ++ 11, поэтому вы можете использовать лямбду вместо этого, код будет короче, но будет иметь точно такую ​​же семантику.

8 голосов
/ 04 июля 2014

Решение, предложенное Робом, теперь действует в C ++ 11 (нет необходимости в Boost):

void doSort()
{
  using namespace std::placeholders;
  std::sort(arr, arr+someSize, std::bind(&MyClass::doCompare, this, _1, _2));
}

Действительно, как упоминал Клаим, лямбды - это вариант, более подробный (вы должны «повторить», что аргументы являются целыми числами):

void doSort()
{
  std::sort(arr, arr+someSize, [this](int l, int r) {return doCompare(l, r); });
}

C ++ 14 поддерживает auto здесь:

void doSort()
{
  std::sort(arr, arr+someSize, [this](auto l, auto r) {return doCompare(l, r); });
}

но, тем не менее, вы объявили, что аргументы передаются копией.

Тогда возникает вопрос "какой из них наиболее эффективен". Этот вопрос был рассмотрен Трэвисом Гокелем: Лямбда против Бинда . Его тестовая программа выдает на моем компьютере (OS X i7)

                        Clang 3.5    GCC 4.9
   lambda                    1001        7000
   bind                3716166405  2530142000
   bound lambda        2438421993  1700834000
   boost bind          2925777511  2529615000
   boost bound lambda  2420710412  1683458000

, где lambda - лямбда, используемая напрямую, а lambda bound - лямбда, хранящаяся в std::function.

Похоже, что лямбды - лучший вариант, что не является сюрпризом, так как компилятору предоставляется информация более высокого уровня, из которой он может получить прибыль.

4 голосов
/ 28 октября 2011

Вы можете использовать boost::bind:

void doSort() {
  std::sort(arr,arr+someSize, boost::bind(&MyClass::doCompare, this, _1, _2));
}
2 голосов
/ 14 декабря 2009

Есть способ сделать то, что вы хотите, но вам нужно использовать небольшой адаптер. Поскольку STL не пишет это для вас, можете написать это самостоятельно:

template <class Base, class T>
struct adaptor_t
{
  typedef bool (Base::*method_t)(const T& t1, const T& t2));
  adaptor_t(Base* b, method_t m)
    : base(b), method(m)
  {}
  adaptor_t(const adaptor_t& copy) : base(copy.base), method(copy.method) {}
  bool operator()(const T& t1, const T& t2) const {
    return (base->*method)(t1, t2);
  }
  Base *base;
  method_t method;
}
template <class Base, class T>
adaptor_t<Base,T> adapt_method(Base* b, typename adaptor_t<Base,T>::method_t m)
{  return adaptor_t<Base,T>(b,m); }

Тогда вы можете использовать его:

doSort() { std::sort(arr,arr+someSize, adapt_method(this, &doCompare)); }
0 голосов
/ 09 октября 2017

Обновление ответа Грэма Ашера: вам не нужно сравнивать, но вы можете напрямую использовать оператор less.

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

using namespace std;

class Qaz {
public:
    Qaz(int aX): x(aX) { }

    bool operator<(const Qaz& aOther) const {
       return x < aOther.x;
    }

int x;
};

int main() {
    std::vector<Qaz> q;
    q.emplace_back(8);
    q.emplace_back(1);
    q.emplace_back(4);
    q.emplace_back(7);
    q.emplace_back(6);
    q.emplace_back(0);
    q.emplace_back(3);
    std::sort(q.begin(),q.end());
    for (auto& num : q)
        std::cout << num.x << "\n";

    char c;
    std::cin >> c;
    return 0;
}
0 голосов
/ 06 февраля 2017

Очень простой способ эффективно использовать функцию-член - это использовать operator <. То есть, если у вас есть функция сравнения, вы можете вызвать ее из оператора <. Вот рабочий пример: </p>

class Qaz
{
public:
Qaz(int aX): x(aX) { }

bool operator<(const Qaz& aOther) const
    {
    return compare(*this,aOther);
    }

static bool compare(const Qaz& aP,const Qaz& aQ)
    {
    return aP.x < aQ.x;
    }

int x;
};

Тогда вам даже не нужно давать имя функции std :: sort:

std::vector<Qaz> q;
q.emplace_back(8);
q.emplace_back(1);
q.emplace_back(4);
q.emplace_back(7);
q.emplace_back(6);
q.emplace_back(0);
q.emplace_back(3);
std::sort(q.begin(),q.end());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...