5

I have a class Person that has a name and an age.

I have a container class called people that stores a set of persons.

I have created two custom comparators to sort by name and by age.

When I store the set containing Persons in my class (People) how do pass the custom comparator in.

for Example

My comparator looks like this

struct compareByName
{
    bool operator()(const Person & Left, const Person & Right)
    {
        return (Left.getName() < Right.getName());
    }
};

in the main if I want to sort a set of persons by name I just do

set<Person, compareByName> peopleByName;

or for age I do

set<Person, compareByAge> peopleByAge;

Where I am having trouble is How do I use this in my people container class I would have something like

class People
{
private:
    set<Person, COMPARATOR> m_people;
}

where COMPARATOR could either be by name or age

2
  • @Ron You can sort a set of objects by custom comparators. Commented Nov 9, 2017 at 18:53
  • Why was this question downvoted? It is a good question. Commented Nov 9, 2017 at 18:56

2 Answers 2

7

You can use std::function as comparator type and then provide particular comparator for constructor:

class People
{
    using PeopleSet = set<Person, std::function<bool(const Person &p1, const Person &p2 )>>;

    People() : people( compareByName() ) {}
    void sortByAge();
private:
    PeopleSet people; 
};

note you cannot change comparator after creation of set, you have to create another instance:

void People::sortByAge()
{
    people = PeopleSet( people.begin(), people.end(), compareByAge() );
}

and that would involve copying or moving whole set. If you want to be able to use both ways at the same time use boost::multi_index instead.

Sign up to request clarification or add additional context in comments.

4 Comments

You could use std::move_iterator to avoid copying all of the people in your sortByAge. If you have access to C++17 you could use std::set::merge to move the nodes directly from one std::set to another.
@MilesBudnek I am not sure std::set::iterator would work with std::move_iterator as it is equal to std::set::const_iterator. This is pretty big topic and I would omit it here for clarity.
@Slava I have been trying to implement this but am getting the error m_people is a non static data member or base class of class. Have you any idea what that means?
@MichaelGrinnell my mistake, I have habbit to name member variables with m_, fixed.
2

You can do it via template:

#include <iostream>
#include <string>
#include <set>

class Person 
{
private:
    std::string name;
    int age;
public:
    Person(std::string name, int age) : name(name), age(age) {};
    std::string getName() const { return name; };
    int getAge() const { return age; };
};

template<class COMPARATOR> class People
{
private:
    std::set<Person, COMPARATOR> m_people;
public:
    void AddPerson(Person const &p)
    {
        m_people.insert(p);
    }
    void PrintPeople()
    {
        for (Person p : m_people)
        {
            std::cout << p.getName() << " - " << p.getAge() << std::endl;
        }
    }
};

struct SortedByName
{
    bool operator()(const Person & Left, const Person & Right)
    {
        return (Left.getName() < Right.getName());
    }
};

struct SortedByAge
{
    bool operator()(const Person & Left, const Person & Right)
    {
        return (Left.getAge() < Right.getAge());
    }
};


int main()
{
    Person p1("Bob", 21);
    Person p2("Jack", 13);
    Person p3("Kath", 33);

    People<SortedByName> ppl1;
    ppl1.AddPerson(p1);
    ppl1.AddPerson(p2);
    ppl1.AddPerson(p3);
    std::cout << "By Name:" << std::endl;
    ppl1.PrintPeople();

    std::cout << std::endl;

    People<SortedByAge> ppl2;
    ppl2.AddPerson(p1);
    ppl2.AddPerson(p2);
    ppl2.AddPerson(p3);
    std::cout << "By Age:" << std::endl;
    ppl2.PrintPeople();

    return 0;
}

Prints:

By Name:
Bob - 21
Jack - 13
Kath - 33

By Age:
Jack - 13
Bob - 21
Kath - 33

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.