In order to use a standard function like std::sort on some standard container Container<T>
struct T{
int x,y;
};
based on the y value, you need to write something like (for example):
std::vector<T> v;
//fill v
std::sort(v.begin(),v.end(),[](const auto& l,const auto& r){
return l.y<r.y;
});
The comparer that was written as lambda function is used too much and re-written again and again during the code for various classes and attributes.
Considering the case where y's type is comparable (either like int or there is an overload for the < operator), is there any way to achieve something like:
std::sort(v.begin(),v.end(),imaginary::less(T::y)); // Imaginary code
Is it possible in C++ to write such a function like less? or anything similar?
I am asking because I remember something like that in some managed language (I am not sure maybe C# or Java). However, I am not sure even about this information if it is true or not.
template<typename T, typename MT>
struct memberwise_less
{
MT T::* const mptr;
auto operator()(const T& left, const T& right) const
{ return (left.*mptr) < (right.*mptr); }
};
template<typename T, typename MT>
memberwise_less<T, MT> member_less(MT T::*mptr)
{
return { mptr };
}
and then you can do
std::sort(v.begin(), v.end(), member_less(&T::y));
Related
Say I define a map with a custom comparator such as
struct Obj
{
int id;
std::string data;
std::vector<std::string> moreData;
};
struct Comparator
{
using is_transparent = std::true_type;
bool operator()(Obj const& obj1, Obj const& obj2) { return obj1.id < obj2.id; };
}
std::map<Obj,int,Comparator> compMap;
is there a good way to ensure that downstream users don't have to implement the comparator to use the map as a map?
for instance my compiler throws an error if I try to pass it to a function with a similar type.
template<class T>
inline void add(std::map<T, int>& theMap, T const & keyObj)
{
auto IT = theMap.find(keyObj);
if (IT != theMap.end())
IT->second++;
else
theMap[keyObj] = 1;
}
add(compMap,newObj); //type error here
EDIT:
I kinda over santitized this to make a generic case. and then overlooked the obvious
template<class T, class Comp, class Alloc>
inline void add(std::map<T, int, Comp, Alloc>& theMap, T const & keyObj)
still having issues with one use not being able to deduce T, but went from 80 erros to 1 so... progress
thanks everyone.
You can typedef the specialised type and use that type inplace of
std::map<...
typedef std::map<Obj,int,Comparator> compMap_t;
inline void add(compMap_t& theMap, Obj const & keyObj)
...
Downstream users either use the type declared by you
using my_important_map = std::map<Obj,int,Comparator>;
or better use functions which take a generic map type,
auto some_function(auto const& map_)
{
//do something with the map and don't care about the ordering
return map_.find(Obj(1));
}
I want to sort some vector depending on an element's member function value like this:
std::vector<cv::Rect> regions;
std::sort(begin(regions), end(regions), [](cv::Rect const& l, cv::Rect const& r){
return l.area() > r.area();
});
Can I do it without directly writing the comparison? I can imagine something like:
std::sort(begin(regions), end(regions), std::compare_greater<cv::Rect::area>);//imaginary code
Is there something like this?
Edit:
cv::Rect::area is a member function that returns float. cv::Rect does not have a comparison operator or, it has one but I want to sort based on another one.
Following on from the comments on the OP; you can refactor the lambda into its own functor for use the std::sort, or you could use a C++03 style by combining the std::greater, std::mem_fun with a bind (possibly std::bind) of some sort etc.; the C++03 style will be cumbersome to work with though.
The functor solution requires the call operator (operator()) to have the appropriate signature; accept the required values and return a bool, the const method and const& parameters are not needed, but by convention usually appear.
struct compare_rect_greater {
bool operator()(cv::Rect const& l, cv::Rect const& r) const
{
return l.area() > r.area();
}
};
// ...
std::vector<cv::Rect> regions;
std::sort(begin(regions), end(regions), compare_rect_greater());
The float return from the area() function will work as expected with the operator >.
But considering the language level, ease of readability etc. your lambda is possible still the better solution.
std::vector<cv::Rect> regions;
std::sort(begin(regions), end(regions), [](cv::Rect const& l, cv::Rect const& r){
return l.area() > r.area();
});
The C++03 style is unwieldily to create and use in this case, I would not venture too far down this road.
You may create a class for that:
template <typename Member>
struct greater_member;
template <typename C, typename Method>
class greater_member<Method (C::*)>
{
explicit greater_member(Method (C::* method)) : mMethod(method) {}
bool operator()(const C& lhs, const C& rhs) const
{
return (lhs.*mMethod)() > (rhs.*mMethod)();
}
private:
Method (C::* mMethod);
}
template <typename C, typename Method>
greater_member<Method (C::*)> make_greater_member(Method (C::* method))
{
return greater_member<Method (C::*)>(method);
}
And then
std::sort(begin(regions), end(regions), make_greater_member(&cv::Rect::area));
Demo
I am trying to make a generic container that would hold objects and their position:
class Vector;
template <typename T>
class Container
{
public:
void insert(const T& t)
{
insertAtPosition(t.getPosition() ,t);
}
private:
void insertAtPosition(const Vector& v, const T& t);
...
} ;
But what if the users' object position getter is not called getPosition?
How can I make this container generic with respect to the way in which the container internally obtains the position of an item?
So far, I have considered 3 approaches, none of them ideal:
Add a std::function<const Vector& (const T& t)> member to the Container.
This is a clean C++ solution, but this function is going to be called very very often and it may result in noticeable performance decrease.
Add a functor object to the container:
class Vector;
template <typename T, typename TGetPosition>
class Container
{
public:
Container(TGetPosition getPosition): getPosition_(getPosition){}
void insert(const T& t)
{
insertAtPosition(getPosition_(t) ,t);
}
private:
void insertAtPosition(const Vector& v, const T& t);
TGetPosition getPosition_;
} ;
I can use the object generator idiom to make it possible to use lambdas:
template <typename T, typename TGetPosition>
Container<T, TGetPosition> makeContainer(TGetPosition getter)
{
return Container<T, TGetPosition>(getter);
}
...
auto container = makeSimpleContainer<Widget>([](const Widget& w)
{
return w.tellMeWhereYourPositionMightBe();
});
There would be no performance overhead, but it would be impossible to get the type of such a container in certain contexts. For example, you could not create a class that would take such a container as a parameter, since decltype would not work, because lambdas cannot be used in unevaluated contexts.
Use #define GETTER getPosition and the user would just change getPosition to whatever he likes. There are so many things wrong with this approach that I don't even know where to start.
Please, is there some other way to do this? Did I miss anything. Any guidance is most welcome!
EDIT:
Regarding solution 2: I have no idea how could we get a the type of a container created with a lambda function. One way would be:
using TContainer = decltype(makeSimpleContainer<Widget>([](const Widget& w)
{
return w.tellMeWhereYourPositionMightBe();
});)
But this doesn't work, because lambdas cannot be used in unevaluated contexts.
Reasonably usable option would be to expect the context to have position_for():
template <class T> struct Container {
size_t insert(T const& x) {
insertAtPosition(position_for(x), x);
}
};
Vector const& position_for(const Widget& w) {
return ...;
}
Container<Widget> c;
c.insert(Widget());
...but designs where the container generates key from the business object usually do not fly well, as to lookup the object one would need to do a dummy one, which may be expensive.
It seems like your second solution will work even if you need to make a class holding a container:
template <typename Container>
struct SomeClass {
SomeClass(const Container &container) : container(container) { }
Container container;
};
int main()
{
auto container = makeSimpleContainer<Widget>([](const Widget& w)
{
return w.tellMeWhereYourPositionMightBe();
});
SomeClass<decltype(container)> test(container);
}
I need to use different compare functions as unary functions, where one of the values is embedded inside the comparator. To do so I created an adaptor class, something like:
template<typename T, typename Compare>
class CompareAdaptor : private Compare
{
public:
CompareAdaptor(T value)
: mValue(value)
{
}
bool operator()(T v) const
{
return Compare::operator()(v, mValue);
}
private:
T mValue;
};
and now I can define a new unary comparator like:
template<typename T>
using EqualTo = CompareAdaptor<T, std::equal_to<T>>;
template<typename T>
using LessEqual = CompareAdaptor<T, std::less_equal<T>>;
My questions is: Is there a simpler way(without using the adaptor class) to define those unary comparators? I think this is a very common problem and probably you have better solutions.
In C++11, this is as good as it gets. But I'd rather expect the predicate to be directly constructed at the call site :
std::find_if(begin(v), end(v), [limit](int i) { return i < limit; });
In C++14, you could use return type deduction to make a factory fuction :
template <class Comp>
auto predicate(typename Comp::second_argument_type rhs) {
return [c = Comp{}, rhs](typename Comp::first_argument_type lhs) {
return c(lhs, rhs);
};
}
Example call : predicate<std::less<int>>(4) returns the function object.
Live on Coliru
#Quentins answer can also be made compilable in C++11 using std::function as the return type which the lambdas are convertible to:
template <class Comp>
std::function<typename Comp::result_type (typename Comp::first_argument_type)> predicate(typename Comp::second_argument_type rhs)
{
return [rhs](typename Comp::first_argument_type lhs){
Comp c{};
return c(lhs, rhs);
};
}
live on coliru
I have a POD with about 30 members of various types and I will be wanting to store thousands of the PODs in a container, and then sort that container by one of those members.
For example:
struct Person{
int idNumber;
....many other members
}
Thousands of Person objects which I want to sort by idNumber or by any other member I choose to sort by.
I've been researching this for a while today and it seems the most efficient, or at least, simplest, solution to this is not use struct at all, and rather use tuple for which I can pass an index number to a custom comparison functor for use in std::sort. (An example on this page shows one way to implement this type of sort easily, but does so on a single member of a struct which would make templating this not so easy since you must refer to the member by name, rather than by index which the tuple provides.)
My two-part question on this approach is 1) Is it acceptable for a tuple to be fairly large, with dozens of members? and 2) Is there an equally elegant solution for continuing to use struct instead of tuple for this?
You can make a comparator that stores a pointer to member internaly so it knows which member to take for comparison:
struct POD {
int i;
char c;
float f;
long l;
double d;
short s;
};
template<typename C, typename T>
struct Comp {
explicit Comp(T C::* p) : ptr(p) {}
bool operator()(const POD& p1, const POD& p2) const
{
return p1.*ptr < p2.*ptr;
}
private:
T C::* ptr;
};
// helper function to make a comparator easily
template<typename C, typename T>
Comp<C,T> make_comp( T C::* p)
{
return Comp<C,T>(p);
}
int main()
{
std::vector<POD> v;
std::sort(v.begin(), v.end(), make_comp(&POD::i));
std::sort(v.begin(), v.end(), make_comp(&POD::d));
// etc...
}
To further generalize this, make make_comp take a custom comparator, so you can have greater-than and other comparisons.
1) Is it acceptable for a tuple to be fairly large, with dozens of members?
Yes it is acceptable. However it won't be easy to maintain since all you'll have to work with is an index within the tuple, which is very akin to a magic number. The best you could get is reintroduce a name-to-index mapping using an enum which is hardly maintainable either.
2) Is there an equally elegant solution for continuing to use struct instead of tuple for this?
You can easily write a template function to access a specific struct member (to be fair, I didn't put much effort into it, it's more a proof of concept than anything else so that you get an idea how it can be done):
template<typename T, typename R, R T::* M>
R get_member(T& o) {
return o.*M;
}
struct Foo {
int i;
bool j;
float k;
};
int main() {
Foo f = { 3, true, 3.14 };
std::cout << get_member<Foo, float, &Foo::k>(f) << std::endl;
return 0;
}
From there, it's just as easy to write a generic comparator which you can use at your leisure (I'll leave it to you as an exercise). This way you can still refer to your members by name, yet you don't need to write a separate comparator for each member.
You could use a template to extract the sort key:
struct A
{
std::string name;
int a, b;
};
template<class Struct, typename T, T Struct::*Member>
struct compare_member
{
bool operator()(const Struct& lh, const Struct& rh)
{
return lh.*Member < rh.*Member;
}
};
int main()
{
std::vector<A> values;
std::sort(begin(values), end(values), compare_member<A, int, &A::a>());
}
Maybe you want to have a look at boost::multi_index_container which is a very powerful container if you want to index (sort) object by different keys.
Create a class which can use a pointer to a Person member data to use for comparison:
std::sort(container.begin(), container.end(), Compare(&Person::idNumber));
Where Compare is:
template<typename PointerToMemberData>
struct Compare {
Compare(PointerToMemberData pointerToMemberData) :
pointerToMemberData(pointerToMemberData) {
}
template<typename Type
bool operator()(Type lhs, Type rhs) {
return lhs.*pointerToMemberData < rhs.*pointerToMemberData
}
PointerToMemberData pointerToMemberData;
};