PDA

View Full Version : qSort doesn't work with member function



ber_44
2nd June 2007, 09:32
I need to pass to qSort() a special lessThan function that works on class members.
Looks like that TT did not know about this C++ limitation when they designed qSort(): http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2

marcel
2nd June 2007, 09:59
What do you mean?
That article was not referring to Qt's signal and slots.
Do you need to pass a pointer to a function to a signal?
That can be done.

Or do you need to just pass a pointer to class member function?

wysota
2nd June 2007, 10:00
I don't really understand... You can just overload the operator<() function or method instead. I haven't tried the option with a function but I don't see any reason why it shouldn't work.

marcel
2nd June 2007, 10:02
void qSort ( RandomAccessIterator begin, RandomAccessIterator end )
Sorts the items in range [begin, end) in ascending order using the heap sort algorithm.
Example:
QList<int> list;
list << 33 << 12 << 68 << 6 << 12;
qSort(list.begin(), list.end());
// list: [ 6, 12, 12, 33, 68 ]
The sort algorithm is efficient on large data sets. It operates in linear-logarithmic time, O(n log n).
This function requires the item type (in the example above, int) to implement operator<().
If of two items neither is less than the other, the items are taken to be equal. It is then undefined which one of the two items will appear before the other after the sort.


As you can see, you don't need any "special" function that operates on member function.
Just put the elements you need to sort in a QList or something similar and implement for that class( items class ) operator <, or operator >, whatever you need, and qSort will take care of the rest.

Regards

Gopala Krishna
2nd June 2007, 10:59
Quote from qt docs for qSort()

void qSort ( RandomAccessIterator begin, RandomAccessIterator end, LessThan lessThan )
This is an overloaded member function, provided for convenience.
Uses the lessThan function instead of operator<() to compare the items.
For example, here's how to sort the strings in a QStringList in case-insensitive alphabetical order:
bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
{
return s1.toLower() < s2.toLower();
}

int doSomething()
{
QStringList list;
list << "AlPha" << "beTA" << "gamma" << "DELTA";
qSort(list.begin(), list.end(), caseInsensitiveLessThan);
// list: [ "AlPha", "beTA", "DELTA", "gamma" ]
}
To sort values in reverse order, pass qGreater<T>() as the lessThan parameter. For example:
QList<int> list;
list << 33 << 12 << 68 << 6 << 12;
qSort(list.begin(), list.end(), qGreater<int>());
// list: [ 68, 33, 12, 12, 6 ]

What else do you want?

ber_44
2nd June 2007, 11:25
Gopala, caseInsensitiveLessThan() is a global function and cannot access class members.
Furthermore, I need to switch between several "less than" functions (depending on user input) so I can't do operator overloading.
I guess QSortFilterProxyModel::lessThan() would do it, but so far I didn't have luck with it.

marcel
2nd June 2007, 11:33
You can overload operator < and let it behave differently according to user input. Just add a few flags to your class and do the sorting according to those flags.

ber_44
2nd June 2007, 11:39
OK, thank you, that would be doable.
Meanwhile I made the proxymodel work,just had to call
proxyModel->sort(0, Qt::AscendingOrder);
after reimplementing lessThan().

Gopala Krishna
2nd June 2007, 11:41
Gopala, caseInsensitiveLessThan() is a global function and cannot access class members.
Furthermore, I need to switch between several "less than" functions (depending on user input) so I can't do operator overloading.
I guess QSortFilterProxyModel::lessThan() would do it, but so far I didn't have luck with it.

You can access public members from a class right? If you want to base the sort on private member, you can add a public member function and then access them.

You can have different functions (global or static member) and pass the required one to the qSort function


bool lessThan1(const Type& t1, const Type& t2)
{
return t1.a() < t2.a(); //or what ever
}

bool lessThan2(const Type& t1, const Type& t2)
{
return t2 < t1;
}

if(userInput == 1)
qSort(list.begin(), list.end(),lessThan1);
else
qSort(list.begin(), list.end(),lessThan2);

You can also use pointer to function and set the pointer to whatever function you want and pass it to qSort()

Gopala Krishna
2nd June 2007, 11:56
OK, thank you, that would be doable.
Meanwhile I made the proxymodel work,just had to call
proxyModel->sort(0, Qt::AscendingOrder);
after reimplementing lessThan().

Oh ok fine. You just wanted to sort. Since you were blaming TT for design issue I thought you wanted to use qSort in your code rather than sort them.
Sorry for misunderstanding!

wysota
2nd June 2007, 13:00
Gopala, caseInsensitiveLessThan() is a global function and cannot access class members.

If you want to access private data, you can declare the sorting function as a friend. Or better yet implement public methods in your class that do different types of comparisons and just call them from within the lessThan implementation. Something like:


bool MyLessThan(const obj &o1, const obj &o2){
return o1.isLessThan(o2, Qt::CaseInsensitive);
}