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.
Related
I want to insert instances of structs into a set. I know that to do this the < operator has to be overloaded so that set can make a comparison in order to do the insertion.
Following program works perfectly.
#include <iostream>
#include<set>
using namespace std;
struct Node
{
int x;
int y;
};
bool operator <( const Node &a,const Node &b)
{
return a.x < b.x ||( a.x == b.x && a.y < b.y);
}
int main()
{
set<Node> s;
Node node;
node.x = 1;
node.y = 2;
s.insert(node);
node.x = 1;
node.y = 0;
s.insert(node);
for( Node node : s)
cout << node.x <<","<< node.y <<endl;
}
Output :
1,0
1,2
But if I want to use custom comparator function,instead of operator overloading I tried this way.
bool Comp( const Node &a,const Node &b)
{
return a.x < b.x ||( a.x == b.x && a.y < b.y);
}
And in main() , I define set as this way.
set<Node, Comp> s; // error
But I got following error :
type/value mismatch at argument 2 in template parameter list for ‘template<class _Key, class _Compare, class _Alloc> class std::set’ set<Node, Comp> s;
Can anyone explain, why there is a error ? How to rectify it ?
You might use function pointer:
bool Comp(const Node &lhs, const Node &rhs)
{
return std::tie(lhs.x, lhs.y) < std::tie(rhs.x, rhs.y);
}
set<Node, bool (*)(const Node&, const Node&)> s(&Comp);
or even better functor (as comparator is fixed):
struct Comp
{
bool operator() (const Node &lhs, const Node &rhs) const
{
return std::tie(lhs.x, lhs.y) < std::tie(rhs.x, rhs.y);
}
};
set<Node, Comp> s;
The 2nd template parameter of std::set expects a type, but Comp is a function, not type. You could
// specify the function pointer type as the 2nd template argument
set<Node, decltype(&Comp)> s(&Comp);
Note that the function pointer is passed to the constructor here. Otherwise the default initialized comparison function pointer would be null pointer.
LIVE
I am trying to find a simple example program that overloads the following operators of a mathematic vector.
Constructor // create
= (equals) // assign
+; -; +=; -= // add sub
*; /; *=; /= // multi divide
++; -- // plus minus
== // compare
>; >=
<; <=
[] // access a value
Cant seem to find any good simple tutorials. I emphasize the simple because I am only learning this stuff now. If someone could link me or even better program a simple overload for just one of the operators as an example would be incredible!
There are a few things to know when you write operators, which are not as often used with other functions.
The assign operators, for example, will return *this because you change the value of the vector:
class v {
public:
double x_, y_;
v& operator += (const v& rhs)
{
_x += rhs._x;
_y += rhs._y;
return *this;
}
};
Another interesting one, the pre ++ and post ++ are different only because of an unused parameter:
class v {
public:
double x_, y_;
v& operator ++ (); // ++v
v& operator ++ (int); // v++
};
The "equal" (assignment) is another one that is tricky when you use pointers. For a vector, it generally won't be a problem, but if you define a vector V and assign it to itself, you have to be careful:
class v {
public:
double x_, y_;
v& operator = (const v& rhs)
{
if(this != &rhs)
{
x_ = rhs.x_;
y_ = rhs.y_;
}
return *this;
}
};
In your case, the if() will most certainly not be useful, but think about doing something like this:
delete p_;
p_ = new foo;
p_->x_ = rhs.p_->x_;
If &rhs == this, then the delete p_ deleted the rhs pointer! That means accessing it on the 3rd line is a bug.
The rest should be easy enough to work with. The compare operators return bool and are const:
class v {
public:
double x_, y_;
bool operator == (const v& rhs) const
{
return x_ == rhs.x_ && y_ == rhs.y_;
}
};
Although, since C++20, you are expected to only declare the three way comparison operator <=> which allows the compiler to implement all the other comparison operators for you. This one returns a negative number (smaller: a < b), 0 (equal: a == b), or a positive number (larger: a > b).
I'm not sure what makes a vector bigger or smaller, I used the length from (0, 0) in this example:
class v {
public:
double x_, y_;
int operator <=> (const v& rhs) const
{
if(x_ == rhs.x_ && y_ == rhs.y_)
{
return 0;
}
return length() > rhs.length() ? 1 : -1;
}
};
Except for the [] operator. There are two versions of that one:
class v {
public:
// I would imagine you'd use an array but as a simple example...
double x_, y_;
double operator [] (int idx) const
{
return idx == 0 ? x_ : y_;
}
v_ref operator [] (int idx)
{
v_ref v(this, idx);
return v;
}
};
As you can see, the non-constant version of the [] operator returns a reference. This is necessary so you can write something like:
r[3] = 7.3;
r[3] returns that reference, then the assignment of the reference is called with 7.3 as the parameter. (Note that we should probably throw an error if you use 3 as the index when you only have 2 values: 0 and 1--this is not shown here)
class v_ref
{
public:
v *p_;
int i_;
v_ref(v *p, int i)
: p_(p), i_(i)
{
}
operator = (double q)
{
// again, I suppose you'd use an array instead!
if(i_ == 0)
{
p_->x_ = q;
}
else
{
p_->y_ = q;
}
}
};
Assuming you want some security, the vector pointer could make use of a reference counter so you know whether a main vector object gets deleted before all of its reference objects...
Another note: I would imagine that your constructor will allocate an array of double (or use an std::vector<double> type...) If you use new, remember to delete in the destructor and that's when the if() in the assignment operator is very important.
I'm trying to use a simple structure as a map key:
class Foo{
.
.
.
struct index{
int x;
int y;
int z;
};
bool operator<(const index a, const index b);
.
.
.
}
And the function itslef:
bool Foo::operator<(const index a, const index b){
bool out = True;
if (a.x == b.x){
if (a.y == b.y){
if (a.z >= b.z) out = false;
}
else if(a.y > b.y) out = false;
} else if (a.x > b.x) out = false;
return out;
}
However, when I compile I get an error:
memMC.h:35: error: 'bool Foo::operator<(Foo::index,
Foo::index)' must take exactly one argument
As I understand this, the compilers wants to compare index to this Foo. How can I overload the operator then?
If you want to compare two indexes, move the overload inside the index structure:
struct index{
int x;
int y;
int z;
bool operator<(const index& a) const;
};
If you want to compare a Foo and an index (I doubt that, but I'll just put this here just in case), remove the second parameter, as it's not needed:
class Foo{
//...
bool operator<(const index& a) const;
};
Note that you should pass the index parameter by reference, to prevent unnecesarry copying.
EDIT: As Als correctly pointed out, this operator should be const.
< is binary infix comparison operator i.e it takes two arguments to compare to each other, So ideally it should be implemented as a free function, However if you implement it as a member function then it will take only one argument.
It shall compare the argument passed as parameter to the object on which the member function is being called.
Your member comparison operator should be like:
class Foo
{
//...
bool operator<(const index& rhs) const
{
/* comparison with *this */
}
//...
};
So suppose I have a class like this one:
class Point
{
private:
int x, y;
public:
void setX(int arg_x) { x = arg_x; }
void sety(int arg_y) { y = arg_y; }
int getX() const { return x; }
int gety() const { return y; }
};
Now I want to have a map like this one:
map<Point, Point> m;
But I need a third parameter. I read in cplusplus that this third parameter is to compare something, but I didn't understand what that something was. Can anyone explain that for me?
You can extend your class with such a method if you don't need a separate compare function
class Point
{
private:
int x, y;
public:
bool operator<( const Point& other) const
{
if ( x == other.x )
{
return y < other.y;
}
return x < other.x;
}
};
By default the stl map orders all elements in it by some notion of ordering. In this case this operator is used. Sometimes you dont have control over the Point class or you might want to use it in two different maps each defines its own ordering. For example one map might sort points by x first and other one might sort by y first. So it might be helpful if the comparison operator is independent of the class Point. You can do something like this.
class Point
{
public:
int x, y;
};
struct PointComparer
{
bool operator()( const Point& first , const Point& second) const
{
if ( first.x == second.x )
{
return first.y < second.y;
}
return first.x < second.x;
}
};
map<Point, Point , PointComparer> m;
What you need is to define an ordering of Point items.
This can be done in different ways :
Overload the operator < for Point
You can provide an overload of the < operator, whose prototype is :
bool operator < (const Point & p_lhs, const Point & p_rhs) ;
For example, for my tests, I used the following one :
bool operator < (const Point & p_lhs, const Point & p_rhs)
{
if(p_lhs.getX() < p_rhs.getX()) { return true ; }
if(p_lhs.getX() > p_rhs.getX()) { return false ; }
return (p_lhs.getY() < p_rhs.getY()) ;
}
This is the easiest way, but it assumes, semantically, that the ordering defined above is the right default one.
Providing a functor
If you are unwilling to provide a < operator, or want to have multiple maps, each one with its own ordering, your solution is to provide a functor to the map. This is the third template parameter defined for the map:
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
The functor must have the following signature :
struct MyCompareFunctor
{
bool operator() (const Point & p_lhs, const Point & p_rhs)
{
// the code for comparison
}
} ;
So, for my tests, I just wrote the following :
struct MyCompare
{
bool operator() (const Point & p_lhs, const Point & p_rhs)
{
if(p_lhs.getX() > p_rhs.getX()) { return true ; }
if(p_lhs.getX() < p_rhs.getX()) { return false ; }
return (p_lhs.getY() > p_rhs.getY()) ;
}
} ;
And used it in my map:
std::map<Point, Point, MyCompare> map ;
Et voilà...
Specializing std::less for Point
I see no point in doing this, but it's always good to know: You can specialize the std::less template structure for your Point class
#include <functional>
namespace std
{
template<>
struct less<Point> : binary_function <Point,Point,bool>
{
bool operator() (const Point & p_lhs, const Point & p_rhs)
{
if(p_lhs.getX() < p_rhs.getX()) { return true ; }
if(p_lhs.getX() > p_rhs.getX()) { return false ; }
return (p_lhs.getY() < p_rhs.getY()) ;
}
} ;
}
This has the same effect as overloading the operator <, at least, as far as the map is concerned.
As for the operator < solution above, semantically, this solution assumes that the ordering defined above is the right default one as far as std:less is concerned.
Note that the default std::less implementation calls the operator < of the is templated type. Having one giving different results than the other could be considered as a semantic error.
When you are using a user defined class as key in std::map, in order to determine the position of the elements in the container the map needs the Comparison class: A class that takes two arguments of the key type and returns a bool.
It is basically, a comparison functor/ function which compares two key values.
You don't need third parameter, you just need the operator== and operator<
bool operator<(const Point& other) const{
if ( x == other.x )
return y < other.y;
return x < other.x;
}
bool operator==(const Point& other) const{
return x == other.x && y == other.y;
}
I think the code above gives a little upgrade to #parapura rajkumar's solutions.
class Point{
private:
int x, y;
public:
bool operator<( const Point& other) const{
return ((x < other.x) || (y < other.y));
}
};
What you are saying as third parameter is called "Comparator" in STL.
For default types as keys youy don't need to provide one as compiler
does that job for you.
But for your-defined types you have to provide it OR else how would compiler maintain
the sort order in map/set etc.
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.