I have the following struct:
struct Foo
{
public:
int getI();
void setI(const int& i);
double getD();
void setDouble(const double& d);
private:
int m_i;
double m_d;
}
Now I want to call a function which sorts a list of Foo
depending on one property.
The sort-function looked like this, when I was using only members in my struct Foo
. But now I need to use getter and setter functions and make the member private.
template <typename T>
void sort(T Foo::* mp, bool asc)
{
std::sort(m_items.begin(), m_items.end(), [=](const Foo& s1, const Foo& s2) { return asc ? ((s1.*mp) < (s2.*mp)) : ((s1.*mp) > (s2.*mp)); });
}
I called it like that:
myList->sort(&Foo:m_i); // or
myList->sort(&Foo:m_d);
Thats not possible anymore, because the members are private and they need to be private. Is there a way of passing the getter-function which can be invoked to do the comparison inside the sort-function?
You can use a pointer-to-member-function:
// (You also need to make your getter functions const because you use `const Foo&` parameters)
template <typename T>
void sort(T(Foo::* pmf)() const, bool asc)
{
std::sort(m_items.begin(), m_items.end(), [=](const Foo& s1, const Foo& s2) { return asc ? ((s1.*pmf)() < (s2.*pmf)()) : ((s1.*pmf)() > (s2.*pmf)()); });
}
// Example: sort(&Foo::getD, true);
I would also recommend making it more generic:
template <typename F>
void sort(F&& projection, bool asc) {
std::sort(m_items.beegin(), m_items.end(), [&projection, asc](const Foo& s1, const Foo& s2) {
return std::invoke(projection, asc ? s1 : s2) < std::invoke(projection, asc ? s2 : s1);
});
}
Which can be called with both pointer-to-member-functions and pointer-to-data-members, as well as lambda expressions if you ever need something more complicated or need to change the API again.