I have seen other people questions but found none that applied to what I'm trying to achieve here.
I'm trying to sort Entities via my EntityManager class using std::sort and a std::vector<Entity *>
/*Entity.h*/
class Entity
{
public:
float x,y;
};
struct compareByX{
bool operator()(const GameEntity &a, const GameEntity &b)
{
return (a.x < b.x);
}
};
/*Class EntityManager that uses Entitiy*/
typedef std::vector<Entity *> ENTITY_VECTOR; //Entity reference vector
class EntityManager: public Entity
{
private:
ENTITY_VECTOR managedEntities;
public:
void sortEntitiesX();
};
void EntityManager::sortEntitiesX()
{
/*perform sorting of the entitiesList by their X value*/
compareByX comparer;
std::sort(entityList.begin(), entityList.end(), comparer);
}
I'm getting a dozen of errors like
: error: no match for call to '(compareByX) (GameEntity* const&, GameEntity* const&)'
: note: candidates are: bool compareByX::operator()(const GameEntity&, const GameEntity&)
I'm not sure but ENTITY_VECTOR is std::vector<Entity *> , and I don't know if that could be the problem when using the compareByX function object ?
I'm pretty new to C++, so any kind of help is welcome.
And a third one comes in... After you edited you question, still one open topic: your comparator takes a const & to the GameEntity class. It should, in order to work with the values of the vector<GameEntity*>, take const GameEntity* arguments instead.
A functor is a class that defines operator() so an object of that class can be "invoked" with the same syntax as calling a function:
struct functor {
bool operator()(Entity const &a, Entity const &b) {
return a.x < b.x;
}
};
If you want that as a member of your Entity class, you'd use a nested class:
class Entity {
float x;
public:
friend class byX;
class byX {
bool operator()(Entity const &a, Entity const &b) {
return a.x < b.x;
}
};
};
Then your sort would look something like this:
std::sort(ManagedEndities.begin(), ManagedEntities.end(), Entity::byX());
Alternatively, if you usually sort Entities by X, you could define operator< for Entity:
class Entity {
float x;
public:
bool operator<(Entity const &other) {
return x < other.x;
}
};
In this case, your use of sort would be a bit simpler:
std::sort(ManagedEntities.begin(), ManagedEntities.end());
Creating the comparison function as a normal member function of the Entity class, however, will lead to a sort invocation that's pretty ugly -- it'll usually need something like std::mem_fun_ref to do the job; it's sufficiently ugly that I'd generally avoid it for real code.
I did see this question, recently, though....
The answer was something in the way of: the function provided to sort should not be a member-function of something. Meaning: it should be a static function, or a free function. In case you declare it a static function, you should still precede it by Entity::compareByX in order to name it correctly.
If you define the order in the class itself, you can, as aJ already said, use a function adapter mem_fun or mem_fun_ref to pour it into a 'free' functor object.
If you want an Entity object to do the comparison, you should provide sort with an object (called a functor or comparator in this case):
struct EntityComp {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.x < b.x;
}
}
...
std::sort( v.begin(), v.end(), EntityComp() );
I believe compareByX should be a static member or lake a look here
In the light of 'what you're trying to achieve', I may do another guess... You want to be able to specify whether to compare your objects by their GameEntity::x member, or by their GameEntity::y member.
The easiest way would be to, as you did, specify a functor for each member:
struct CompareX {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.x < b.x;
}
};
struct CompareY {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.y < b.y;
}
};
CompareX compx; // create a compare object
std::sort( v.begin(), v.end(), compx );
The 'flexible' yet more cumbersome way would be to create a template functor:
#include <iostream>
using namespace std;
// a mockup of your class
struct GameEntity { float x, y, z; };
// just to be able to print it...
ostream& operator<<( ostream& o, const GameEntity& g ) {
return o << "(" << g.x << ", " << g.y << ", " << g.z << ")";
}
// cumbersome starts here...
typedef float (GameEntity::*membervar);
// a 'generic' float-member comparator
template< membervar m > struct CompareBy {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.*m < b.*m ;
}
};
// example code
int main() {
using namespace std;
GameEntity v[] = { {1,0,0}, {2,0,1}, {3,-1,2} };
GameEntity* vend = v + sizeof(v)/sizeof(v[0]);
sort( v, vend, CompareBy< &GameEntity::x >() );
copy( v, vend, ostream_iterator<GameEntity>( cout, "\n" ) );
}
try this..
class CompareByX
{
operator ()(const GameEntity &a, const GameEntity &b) { ... };
};
...
std::sort( this->begin(), this->end(), CompareByX);
In a nutshell, a functor is a function object - the STL looks specifically for an operator () that takes in the two parameters I've specified. If you're new to C++, I suggest you look up operators and functors - they're pretty handy even outside STL.
Edit: Jerry's answer is better, and more comprehensive.
Related
Given the class
class objects {
public:
bool compareArea (const objects& obj) const { return this->area < obj.area; }
private:
double area;
};
I want to sort a
list<shared_ptr<objects>> myObjects;
I cannot use a lambda (since my toolchain's C++11 support is incomplete). Thus, I tried the following:
using namespace placeholders;
myObjects.sort(bind(&objects::compareArea,_1,_2));
This line is called from another file (not from a class member!). The problem is, that compareArea requires two objects as input. But I give two shared pointer to objects to it. Is there an easy way of how to include the dereferencing of the pointers into the sort-call? I want the objects::compareArea(..) function to stay as it is. I do not want this kind of solution
bool compareArea (const shared_ptr<objects>& ptr1, const shared_ptr<objects>& ptr2) {
return ptr1->area > ptr2->area;
}
// in same source-file:
myObjects.sort(bind(compareArea,_1,_2));
where compareArea is no member-function of objects. Actually an operator overloading of < would be my favourite solution.
I would strongly suggest that you never store any kind of pointer in a container.
Instead, make a handle class which supports the required arithmetic and comparison operators.
It makes for code that's easier to reason about:
class objects {
public:
objects(double w, double h) : area(w * h) {}
bool operator<(const objects& r) const { return this->area < r.area; }
private:
double area;
};
struct object_handle
{
object_handle(shared_ptr<objects> const& ptr) : ptr_(ptr) {}
static object_handle create(double w, double h) { return make_shared<objects>(w,h); }
bool operator < (object_handle const& r) const {
return *ptr_ < *r.ptr_;
}
shared_ptr<objects> ptr_;
};
int main() {
std::vector<object_handle> mylist;
mylist.push_back(object_handle::create(10, 7));
mylist.push_back(object_handle::create(2, 5));
std::sort(mylist.begin(), mylist.end());
}
Lambdas are just syntactic sugar for a class with operator(), so you can very easily write one directly (especially if you don't need captures):
struct Comparator
{
bool operator() (const shared_ptr<objects> &lhs, const shared_ptr<objects> &rhs) const
{
return lhs->compareArea(*rhs);
}
};
myObjects.sort(Comparator());
When declaring a std::map with a custom class is there any difference if I use a comparator as opposed to just implementing the less than operator for the class? Is one 'wrong' or considered bad?
Any difference between this:
std::map <MyClass, float, CompareMyClass> myMap2;
And this:
std::map <MyClass, float> myMap; // where MyClass has the less than operator implemented
Full Code:
class MyClass
{
public:
bool operator()(const MyClass& a, const MyClass& b) const
{
return a.value_ < b.value_;
}
bool operator<(const MyClass& myClass) const
{
return value_ < myClass.value_;
}
private:
friend struct CompareMyClass;
float value_;
};
struct CompareMyClass
{
bool operator()(const MyClass& a, const MyClass& b) const
{
return a.value_ < b.value_;
}
};
int main(int argv, char** args)
{
std::map <MyClass, float> myMap;
MyClass a;
myMap[a] = 1.99;
std::map <MyClass, float, CompareMyClass> myMap2;
MyClass b;
myMap[b] = 1.99;
system("PAUSE");
return 0;
}
If you provide an operator<, its behaviour should not be surprising. Now, for different uses, you might want to sort a record by different criteria, and for such a record, any operator< would always have surprising behaviour. In such a case, it is better to create a comparator who's name already gives a hint how it sorts, because it makes it explicit how a map (or other things) are sorted.
Suppose we have class name Default that have two attribute x and y.
The default operation to compare object is using attribute x.
When we would like to compare this object using other attribute y,
1. Is it safe to create new derive class that can compare by using attribute y and then casting pointer from Default to that new class and compare object?
2. What is alternative way to do this without decreasing the performance of operation?
The requirement is we can not change the the signature of sorting algorithm to pass on function pointer to difference comparator.
By the way this method is required no cost for convert or copy data.
class Default {public:int x; int y;};
class Compare1 : public Default {};
bool operator < (const Default &left,const Default &right)
{
return left.x < right.x;
}
bool operator < (const Compare1 &left,const Compare1 &right)
{
return left.y < right.y;
}
template<typename T>
int *sort_element(const T *data, int size)
{
int *permute;
//... do some sorting by using < comparator ...
return permute;
}
int main(){
Default *obj;
int obj_size;
//… initialize obj and obj size..
// sorting object with default order.
int *output_default = sort_element(obj, obj_size)
// sorting with customize comparator.
Compare1 *custom1 = static_cast<Compare1*>(obj);
int *output_custom1 = sort_element(custom1, obj_size);
}
Better is passing a functor or lambda as compare function when you're sorting them. Your sort function must accept a function:
template<typename T, typename F>
int *sort_element(const T *data, int size, F comp)
{
....
if (comp(a, b))
....
...
}
Then
// Sort by x
sort_element(..., [](const Default &a, const Default &b) {
return a.x < b.x;
});
// Sort by y
sort_element(..., [](const Default &a, const Default &b) {
return a.y < b.y;
});
If you haven't C++11 you can use function object (functor) instead:
struct fx
{
bool operator()(const Default &a, const Default &b) const
{
return a.x < b.x;
}
};
struct fy
{
bool operator()(const Default &a, const Default &b) const
{
return a.y < b.y;
}
};
// Sort by x
sort_element(..., fx());
// Sort by x
sort_element(..., fy());
Forget your second class Compare1 and Remove it.
I have a function in a struct that sorts a vector in the struct. But to compare two elements in the vector, I need value of another variable inside the same struct. I was wondering where I should keep the operator overload or the compare function for this sort to work. I've given a sample in the following paste.
#include<vector>
#include<algorithm>
struct Square{
int color; //value 1 to 10
};
struct State{
vector<Square> list;
int color_weight[] = {4,3,5,2,4,1,6,4,5,9}; //These values keep changing.
bool operator<(Square& a, Square& b);
void sortTheList();
};
bool State::operator<(Square& a, Square& b){
if (color_weight[a.color]< color_weight[b.color]){
return true;
}
return false;
}
void Square::sortTheList(){
sort(list.begin(),list.end());
}
This doesn't work, of course. I've tried many other signatures and scope for the comparison function but nothing seems to work.
Any idea what can be done here?
You would use a comparator that keeps a reference to the extra state that it needs, instead of operator<. Something like this:
struct CompareWeight {
CompareWeight(int const * weight) : weight(weight) {}
bool operator()(Square const & lhs, Square const & rhs) {
return weight[lhs.color] < weight[rhs.color];
}
int const * weight;
};
void Square::sortTheList() {
std::sort(list.begin(), list.end(), CompareWeight(color_weight));
}
class Point
{
int x;
}
static Point referencePoint;
struct Comparator
{
bool AbsComparator(const Point& p1, const Point& p2)
{
return abs(p1.x - referencePoint.x) < abs(p2.x - referencePoint.x);
}
};
list<Point> points;
points.sort(Comparator::AbsComparator);
But I CANNOT use a static referencePoint for multithreading safe, is there any other way??
Thanks.
Make it part of Comparator:
struct Comparator
{
Point referencePoint;
Comparator(Point referencePoint): referencePoint(referencePoint) {}
Comparator(const Comparator& rhs) {
referencePoint = rhs.referencePoint;
}
bool operator()(const Point& p1, const Point& p2) const
{
return abs(p1.x - referencePoint.x) < abs(p2.x - referencePoint.x);
}
};
...
points.sort(Comparator(refP));
Why not simply save the referencePoint or rather the integer value inside Point as a member inside your Comparator, that way you always access it in the comparator function.
Avoid global variables. That is start of writing multi-threaded code.
Use local variables instead:
Point referencePoint(10,20); //use local variable!
points.sort(Comparator(referencePoint));
Or simpy this,
points.sort(Comparator(Point(10,20)));
where Comparator is a functor defined as:
struct Comparator
{
Point referencePoint;
explicit Comparator(const Point & pt) : referencePoint(pt) {}
bool operator() (const Point& p1, const Point& p2) const
{
return abs(p1.x - referencePoint.x) < abs(p2.x - referencePoint.x);
}
};
You're done!
Notice the implementation of operator(). This makes the class a functor.
You can simply store this variable, either in a destructured or structured manner.
// destructured (only store what you need)
class ReferenceComparator {
public:
explicit ReferenceComparator(int x): _x(x) {}
explicit ReferenceComparator(Point const& p): _x(p.x) {}
bool operator()(Point const& left, Point const& right) const {
return abs(left.x - _x) < abs(right.x - _x);
}
private:
int _x;
}; // class ReferenceComparator
And then use it as:
list.sort(ReferenceComparator(myReferencePoint));
I would advise not using a list if you need sorting through. list are not good at it...