struct MyStruct {
ANYTYPE m_a;
ANYTYPE m_b;
std::string m_s;
};
class CAny {
//...
CArray<MyStruct , MyStruct>array;
//..
};
void CAny::Sort(int type, BOOL bAscending)
{
//type - индекс, обозначает член MyStruct, по которому производить сортировкуswitch(type) {
case 1:
//...сортировать по m_abreak;
case 2:
//...сортировать по m_bbreak;
default:
//...сортировать по m_sbreak;
}
qsort(array.GetData(), array.GetSize(), sizeof(MyStruct), compare);
//compare - адрес СТАТИЧЕСКОЙ ф-ции сортировки
}
Получается, что я должен определить ф-ю сортировки для каждого члена MyStruct.
А учитывая, что сортировка может быть задана как по возрастанию, так и по убыванию, то получается по 2 ф-ции на каждого члена:
class CAny {
//...static int __cdecl CompareAscA(const void* p1, const void* p2);
static int __cdecl CompareDescA(const void* p1, const void* p2);
static int __cdecl CompareAscB(const void* p1, const void* p2);
static int __cdecl CompareDescB(const void* p1, const void* p2);
static int __cdecl CompareAscS(const void* p1, const void* p2);
static int __cdecl CompareDescS(const void* p1, const void* p2);
//...
};
При этом
Я, конечно, могу завести статический член в MyStruct, который буду инициализировать в ф-ции Sort(),
и который будет определять, по какому полю MyStruct сортировать. Но проблема в том, что он будет статический. То есть асинхронная сортировка нескольких таких приведет к какой-то лаже.
Возможно, есть какое-то простое решение, но мне чего-то пока не сообразить.
Спасибо
17.02.05 17:23: Перенесено модератором из 'C/C++. Прикладные вопросы' — Павел Кузнецов
Здравствуйте, Mikka77, Вы писали:
M>Добрый вечер. M>Предположим, имеется такой код:
M>
M>struct MyStruct {
M> ANYTYPE m_a;
M> ANYTYPE m_b;
M> std::string m_s;
M>};
M>class CAny {
M>//...
M> CArray<MyStruct , MyStruct>array;
M>//..
M>};
M>void CAny::Sort(int type, BOOL bAscending)
M>{
M> //type - индекс, обозначает член MyStruct, по которому производить сортировку
M> switch(type) {
M> case 1:
M> //...сортировать по m_a
M> break;
M> case 2:
M> //...сортировать по m_b
M> break;
M> default:
M> //...сортировать по m_s
M> break;
M> }
M> qsort(array.GetData(), array.GetSize(), sizeof(MyStruct), compare);
M> //compare - адрес СТАТИЧЕСКОЙ ф-ции сортировки
M>}
M>
M>Получается, что я должен определить ф-ю сортировки для каждого члена MyStruct. M>А учитывая, что сортировка может быть задана как по возрастанию, так и по убыванию, то получается по 2 ф-ции на каждого члена: M>
M>При этом
M>Я, конечно, могу завести статический член в MyStruct, который буду инициализировать в ф-ции Sort(), M>и который будет определять, по какому полю MyStruct сортировать. Но проблема в том, что он будет статический. То есть асинхронная сортировка нескольких таких приведет к какой-то лаже.
M>Возможно, есть какое-то простое решение, но мне чего-то пока не сообразить. M>Спасибо
Забыл там дописать, что в MyStruct некоторые поля одного типа, соответственно не имеет смысла писать идентичные ф-ции сортировки для каждого поля
Здравствуйте, Mikka77, Вы писали:
Итак, pointers to members вступают в игру!
#include <vector>
#include <algorithm>
#include <string>
//Предикат, осуществляющий сравнение двух объектов по определенному полюtemplate<class T, class M>
class pmem_cmp_
{
M T::* pmem_;//указатель на членbool bAscending_;
public:
pmem_cmp_(M T::* pmem, bool bAscending) : pmem_(pmem), bAscending_(bAscending) {}
bool operator() (const T& lhs, const T& rhs) const
{
if(bAscending_)
return lhs.*pmem_ < rhs.*pmem_;
else
return rhs.*pmem_ < lhs.*pmem_;
}
};
//функция, упрощающая синтаксис при создании объекта - предиката:
//вместо pmem_cmp_<MyStruct, int>(&MyStruct::n_) теперь можно написать pmem_cmp(&MyStruct::n_) template<class T, class M>
inline pmem_cmp_<T, M> pmem_cmp(M T::* pmem, bool bAscending) { return pmem_cmp_<T, M>(pmem, bAscending); }
struct MyStruct
{
int n_;
double d_;
std::string s_;
};
//извини, но MFC-шные контейнеры я не перевариваю ;-)class CAny
{
std::vector<MyStruct> array;
public:
void Sort(int type, bool bAscending);
};
void CAny::Sort(int type, bool bAscending)
{
switch(type)
{
case 1:
std::sort(array.begin(), array.end(), pmem_cmp(&MyStruct::n_, bAscending));
break;
case 2:
std::sort(array.begin(), array.end(), pmem_cmp(&MyStruct::d_, bAscending));
break;
case 3:
std::sort(array.begin(), array.end(), pmem_cmp(&MyStruct::s_, bAscending));
break;
};
}
Кстати в CAny::Sort можно сразу передавать указатель на член, по которому нужно сортировать, тогда реализации этой функции будет состоять вообще из одной строки.
Единственное требование — для элементов MyStruct, по которым будет производится сортировка, должен быть определен operator <().
Про остальное тебе уже расказали, а еще скажу что MyStruct с помощью qsort сортировать нельзя ибо MyStruct содержит std::string и как следствие не является POD типом.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Bell, Вы писали:
B>Здравствуйте, Mikka77, Вы писали: B>Итак, pointers to members вступают в игру!
Несколько вызовов std::sort с предикатами разных типов приводят к излишнему раздуванию кода.
На мой взгляд лучше не плодить типы предикатов для каждого поля, а сделать чтобы предикаты одного типа могли сортировать по любому полю. Примерно так:
Здравствуйте, WolfHound, Вы писали:
WH>Про остальное тебе уже расказали, а еще скажу что MyStruct с помощью qsort сортировать нельзя ибо MyStruct содержит std::string и как следствие не является POD типом.
В общем верно,
но если сильно надо то можно и qsort. Надо лишь проверить устройство std::string для вашего компилятора.
В большинтсве имплементаций — можно. В 99% случаев raw swap эквивалентен логическому swap.
Disclaimer: это из разряда "если отдаешь себе отчет".