I have a simple MyElement
class, and I would like to use a bool MyElement::SomeMethod(...) {...}
as the custom comparator for a std::set
of MyElement
items.
I have made my research, and I am already aware of some alternative solutions, which I list below.
I also know how to change, for example, the comparator with std::greater
instead of the default std::less
, with code like this:
std::set<MyElement, std::greater<MyElement> > s;
My exact problem is that I want to use bool MyElement::SomeMethod(...) {...}
as custom comparator.
The only solution I come up with is analogous to the last one in the list below, namely the solution for boolean function:
using Cmp = std::integral_constant<decltype(&MyElement::SomeMethod),
&MyElement::SomeMethod>;
std::set<MyElement, Cmp> my_EventInSet_set;
This solution only works for a static
MyElement::SomeMethod
, though.
I am wondering if there is an analgous, or more concise, way for a non static method.
List of alternative solutions:
method for C 20
auto cmp = [](const MyElement& lhs, const MyElement& rhs) { return ... };
std::set<MyElement, decltype(cmp)> s;
method for C 11
auto cmp = [](const MyElement& lhs, const MyElement& rhs) { return ... };
std::set<MyElement, decltype(cmp)> s(cmp);
function instead of a lambda
bool cmp(const MyElement& lhs, const MyElement& rhs) { return ...; }
and then
std::set<MyElement, decltype(cmp)*> s(cmp);
or
std::set<int, decltype(&cmp)> s(&cmp);
struct and operator()
struct cmp {
bool operator() (const MyElement& lhs, const MyElement& rhs) const {
return ...
}
};
and then
std::set<MyElement, cmp> s;
boolean function
bool cmp(const MyElement& lhs, const MyElement& rhs) {
return ...;
}
and then
#include <type_traits>
using Cmp = std::integral_constant<decltype(&cmp), &cmp>;
std::set<MyElement, Cmp> s;
CodePudding user response:
This is a bit subjective, but to me the cleanest option is struct operator() to match the definition of std::less
, the default comparator for std::set
. There's nothing wrong with the other options but a comparison functor is a common pattern and easy to recognize.
You could also define MyElement::operator<
, and then you wouldn't need to pass in a comparator separately.
CodePudding user response:
You can use std::mem_fn
to bind a member function.
#include <functional>
#include <iostream>
#include <set>
#include <utility>
struct S {
int i;
bool cmp(const S& other) const { return i < other.i; }
};
template <typename T, typename Cmp>
std::set<T, Cmp> make_set(Cmp&& cmp) {
return std::set<T, Cmp>{std::forward<Cmp>(cmp)};
}
int main(int argc, char* argv[]) {
auto s = make_set<S>(std::mem_fn(&S::cmp));
s.emplace(S{0});
std::cout << s.begin()->i << std::endl;
return 0;
}