Russian Qt Forum

Qt => Общие вопросы => Тема начата: Cyrax от Январь 06, 2008, 14:19



Название: qSort: метод класса в качестве функции сравнения...
Отправлено: Cyrax от Январь 06, 2008, 14:19
Может, это и C++, но вопрос такой:
Имеется класс  Manager c методом compareIdsByNum_lessThan, сравнивающим 2 целых числа (идентификатора) на основе информации из объекта этого класса (т.е. сравнение происходит с учётов некоторых характеристик этих идентификаторов, а не просто "сравнить 2 числа"):
Цитировать
bool compareIdsByNum_lessThan(const int &id_1, const int &id_2);
В одном из методов класса Manager сортирую элементы списка (целые числа - идентификаторы) функцией qSort. parameterEndUse_index - список QList этих идентификаторов (целых чисел).

Цитировать
qSort(this->parameterEndUse_index.begin(), this->parameterEndUse_index.end(), Manager::compareIdsByNum_lessThan);
Результат:
Цитировать
argument of type `bool (Manager::)(const int&, const int&)' does not match `bool (Manager::*)(const int&, const int&)'

Ставим "указатель" на метод класса:
Цитировать
qSort(this->parameterEndUse_index.begin(),
        this->parameterEndUse_index.end(),
        &Manager::compareIdsByNum_lessThan);
Результат:
Цитировать
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h   instantiated from `void qSort(RandomAccessIterator, RandomAccessIterator, LessThan) [with RandomAccessIterator = QList<int>::iterator, LessThan = bool (Manager::*)(const int&, const int&)]'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'

Одна и та же ошибка аж в 6 экземплярах...

Делаем то же самое через предварительно объявленный и проинициализированный указатель на метод:

bool (Manager::*lessThan)(const int &id_1, const int &id_2);
lessThan = &Manager::compareIdsByNum_lessThan;
qSort(this->parameterEndUse_index.begin(),
        this->parameterEndUse_index.end(),
        lessThan);

Результат - тот же:
Цитировать
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h   instantiated from `void qSort(RandomAccessIterator, RandomAccessIterator, LessThan) [with RandomAccessIterator = QList<int>::iterator, LessThan = bool (Manager::*)(const int&, const int&)]'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'
c:/GPL/Qt/4.3.1/include/QtCore/../../src/corelib/tools/qalgorithms.h must use .* or ->* to call pointer-to-member function in `lessThan (...)'

Что за чудеса ?


Название: Re: qSort: метод класса в качестве функции сравнения...
Отправлено: pastor от Январь 06, 2008, 15:30
Вынеси метод compareIdsByNum_lessThan из класса Manager или попробуй объявить её как static


Название: Re: qSort: метод класса в качестве функции сравнения...
Отправлено: Cyrax от Январь 06, 2008, 16:51
Цитировать
Вынеси метод compareIdsByNum_lessThan из класса Manager или попробуй объявить её как static
Ни то, ни другое не получится, т.к. метод compareIdsByNum_lessThan при сравнении использует информацию, которую содержит объект класса Manager...


Название: Re: qSort: метод класса в качестве функции сравнения...
Отправлено: pastor от Январь 06, 2008, 18:29
Со static работает 100 процентов, при условии что нет ображения к нестатическим данным класса.

По теме: имхо, так сделать не получиться (см. исходники qSortHelper).

Вызов метода сравнения элементов не заточен для работы с методами класса или указателями на них.


Название: Re: qSort: метод класса в качестве функции сравнения...
Отправлено: Cyrax от Январь 06, 2008, 21:34
A STL-кий sort сработает ?


Название: Re: qSort: метод класса в качестве функции сравнения...
Отправлено: Cyrax от Январь 12, 2008, 13:25
Цитировать
Вызов метода сравнения элементов не заточен для работы с методами класса или указателями на них.
Не то, чтобы не заточен. Просто в случае передачи нестатического метода какого-либо объекта qSort'у по-любому придётся передать ещё один параметр - объект, из которого следует вызывать метод...

Собственно, STL'кий sort должен реагировать на такие попыткаи аналогичным образом...


Название: Re: qSort: метод класса в качестве функции сравнения...
Отправлено: Вячеслав от Январь 12, 2008, 23:09
Я тут недавно рассматривал штуку http://www.codeproject.com/KB/cpp/FastDelegate.aspx (http://www.codeproject.com/KB/cpp/FastDelegate.aspx) 
вот кусок демки
Код:
    printf("-- FastDelegate demo --\nA no-parameter 
             delegate is declared using FastDelegate0\n\n");             
           
    FastDelegate0 noparameterdelegate(&SimpleVoidFunction);

    noparameterdelegate();
    // invoke the delegate - this calls SimpleVoidFunction()


    printf("\n-- Examples using two-parameter delegates (int, char *) --\n\n");

    typedef FastDelegate2<int, char *> MyDelegate;

    MyDelegate funclist[10]; // delegates are initialized to empty

    CBaseClass a("Base A");
    CBaseClass b("Base B");
    CDerivedClass d;
    CDerivedClass c;
   
  // Binding a simple member function

    funclist[0].bind(&a, &CBaseClass::SimpleMemberFunction);
  // You can also bind static (free) functions

    funclist[1].bind(&SimpleStaticFunction);
  // and static member functions

    funclist[2].bind(&CBaseClass::StaticMemberFunction);
  // and const member functions

    funclist[3].bind(&a, &CBaseClass::ConstMemberFunction);
  // and virtual member functions.

    funclist[4].bind(&b, &CBaseClass::SimpleVirtualFunction);

  // You can also use the = operator. For static functions,

  // a fastdelegate looks identical to a simple function pointer.

    funclist[5] = &CBaseClass::StaticMemberFunction;

  // The weird rule about the class of derived

  // member function pointers is avoided.

  // Note that as well as .bind(), you can also use the

  // MakeDelegate() global function.

    funclist[6] = MakeDelegate(&d, &CBaseClass::SimpleVirtualFunction);

  // The worst case is an abstract virtual function of a

  // virtually-derived class with at least one non-virtual base class.

  // This is a VERY obscure situation, which you're unlikely to encounter

  // in the real world, but it's included as an extreme test.

    funclist[7].bind(&c, &CDerivedClass::TrickyVirtualFunction);
  // ...BUT in such cases you should be using the base class as an

  // interface, anyway. The next line calls exactly the same function.

    funclist[8].bind(&c, &COtherClass::TrickyVirtualFunction);

  // You can also bind directly using the constructor

    MyDelegate dg(&b, &CBaseClass::SimpleVirtualFunction);

    char *msg = "Looking for equal delegate";
    for (int i=0; i<10; i++) {
        printf("%d :", i);
        // The ==, !=, <=,<,>, and >= operators are provided

        // Note that they work even for inline functions.

        if (funclist[i]==dg) { msg = "Found equal delegate"; };
        // There are several ways to test for an empty delegate

        // You can use if (funclist[i])

        // or          if (!funclist.empty())

        // or          if (funclist[i]!=0)

        // or          if (!!funclist[i])

        if (funclist[i]) {
            // Invocation generates optimal assembly code.

            funclist[i](i, msg);
        } else {
            printf("Delegate is empty\n");
        };
    }

Как видно жрет и статики и обычные методы ;) Вроде и boost::bind совместима ..... Не пойдет как вариант ?


Название: Re: qSort: метод класса в качестве функции сравнения...
Отправлено: Cyrax от Январь 12, 2008, 23:58
Спасибо, но я уже свой сортировщик написал.
Разбираться сейчас - время жалко..