jake
jake

Reputation: 284

Sort Over Different Class Members

I have a class that includes several members of type double.

Suppose I need to make a function that re-orders a vector of class objects based on the values of one of the members on the class. So:

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

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

But now, I want to be able to do the same re-ordering, but according to values of the other members of the class (y and z in the code above).

Instead of making two more functions that are identical to the first one, except with all references to x changed to y or z, I would like to make a single polymorphic function that can re-order the vector according to any of the members of myClass.

What is the best way to do this?

Upvotes: 1

Views: 107

Answers (2)

Derrick Turk
Derrick Turk

Reputation: 4336

I agree with everyone suggesting alternate approaches given the problem description here.

However, if you ever really have the need to access a class member chosen at runtime, you can use a pointer-to-member type. There is usually a more elegant way to accomplish the effect you want, though.

For example:

#include <iostream>
#include <vector>

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

void operate_on_member(const X& 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 auto& x : xs)
        operate_on_member(x, &X::a);
    for (const auto& x : xs)
        operate_on_member(x, &X::b);
    for (const auto& x : xs)
        operate_on_member(x, &X::c);
}

Upvotes: 1

Keith
Keith

Reputation: 6834

You can use std::sort, combined with a lambda and a pointer to member thus:

#include <vector>
#include <algorithm>

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

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

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

    return 0;
}

And you could also templatise the sort using:

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

Upvotes: 2

Related Questions