Сортировка по разным членам класса

#c

#c

Вопрос:

У меня есть класс, который включает в себя несколько членов типа double .

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

 class myClass{
    ...
    public:
       double x, y, z;
    ...
 }

void SpecialSort_x(std::vector<myClass>amp; vec) {
    // re-order stuff according to values of vec[i].x
    ...
}
 

Но теперь я хочу иметь возможность выполнять такое же переупорядочение, но в соответствии со значениями других членов класса ( y и z в приведенном выше коде).

Вместо создания еще двух функций, идентичных первой, за исключением того, что все ссылки x изменены на y или z , я хотел бы создать единую полиморфную функцию, которая может изменять порядок вектора в соответствии с любым из членов myClass .

Каков наилучший способ сделать это?

Комментарии:

1. Почему бы вам просто не использовать std::sort с пользовательской функцией сравнения (object)?

2. Давайте начнем с вопроса, почему вы не используете std::sort .

3. Расширение dyp's comment, use std::sort` с помощью лямбды.

4. @Jon, @ Deduplicator, переупорядочение — это не просто сортировка. Для этого требуется больше, чем одна функция сравнения (насколько я могу судить). Кроме того, я хотел бы, чтобы функция в будущем делала больше, чем просто переупорядочивала. Возможно, возвращает некоторые значения на основе значений конкретного рассматриваемого члена класса.

5. std::sort это правильный путь, но чтобы ответить на ваш заданный вопрос, вы могли бы использовать аргумент типа указатель на член double myClass::* .

Ответ №1:

Вы можете использовать std::sort , в сочетании с лямбдой и указателем на член, таким образом:

 #include <vector>
#include <algorithm>

class MyClass
{
public:
    double x, y, z;
};
typedef double MyClass::* Field;

void specialSort(std::vector<MyClass>amp; vec, Field field) 
{
    std::sort(vec.begin(), vec.end(), [field](const MyClass amp; a, const MyClass amp; b) -> bool
    {
        return a.*field < b.*field;
    });
}

int main()
{
    std::vector<MyClass> vec;
    Field member = amp;MyClass::x;
    specialSort(vec, member);

    return 0;
}
 

И вы также можете создать шаблон для сортировки с помощью:

 template<class T>
void specialSort(std::vector<T>amp; vec, double T::* field)
{
    std::sort(vec.begin(), vec.end(), [field](const Tamp; a, const Tamp; b) -> bool
    {
        return a.*field < b.*field;
    });
}
 

Ответ №2:

Я согласен со всеми, предлагающими альтернативные подходы, учитывая описание проблемы здесь.

Однако, если вам когда-нибудь действительно понадобится получить доступ к члену класса, выбранному во время выполнения, вы можете использовать тип указателя на член. Однако обычно существует более элегантный способ добиться желаемого эффекта.

Например:

 #include <iostream>
#include <vector>

struct X {
    double a;
    double b;
    double c;
};

void operate_on_member(const Xamp; x, double X::*pm)
{
    std::cout << x.*pm << 'n';
}

int main()
{
    std::vector<X> xs {
        { 1, 2, 3 },
        { 4, 5, 6 },
        { 7, 8, 9 }
    };

    for (const autoamp; x : xs)
        operate_on_member(x, amp;X::a);
    for (const autoamp; x : xs)
        operate_on_member(x, amp;X::b);
    for (const autoamp; x : xs)
        operate_on_member(x, amp;X::c);
}