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.
If you had access to C++20 or newer, you wouldn't need a custom sorting function for this, as the standard function is flexible enough to do this as a oneliner:
std::ranges::sort(m_items, {}, &Foo::getI); // Ascending
std::ranges::sort(m_items, std::greater{}, &Foo::getI); // Descending
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With