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.
Related
I hope the title describes my problem completely.
Running the code I get an error:
error C2678: binary '==':no operator found which takes a left-hand operand of tpye 'A' (or there is no acceptable conversion)"
Where is the mistake and how can I fix the problem???
class A
{
private: //Dummy Values
int x;
int y;
}
class B
{
private:
vector <A> dataHandler;
public:
bool isElement(A element);
//Should return true if element exists in dataHandler
}
bool B::isElement(A element)
{
int length = dataHandler.size();
for(int i = 0; i<length; i++)
{
if(dataHandler[i] == element) //Check if element is in dataHandler
return true;
}
return false;
}
Within isElement you have
if(dataHandler[i] == element)
This is attempting to compare two A instances using operator==, but your A class doesn't implement any such operator overload. You probably want to implement one similar to this
class A
{
private: //Dummy Values
int x;
int y;
public:
bool operator==(A const& other) const
{
return x == other.x && y == other.y;
}
};
Also, isElement can be rewritten using std::find instead of a for loop
bool B::isElement(A const& element) const
{
return std::find(dataHandler.begin(), dataHandler.end(), element) != dataHandler.end();
}
Compiler tells you everything. Define operator== for class A. Update class A to something like this:
class A
{
private: //Dummy Values
int x;
int y;
public:
bool operator==(A const& rhs) const
{
return x == rhs.x && y == rhs.y;
}
};
you have to write your own == operator for class A, something like
bool operator==(const A &rhs) const
{
return this->x == rhs.x && this->y == rhs.y;
}
otherwise there's no way to know how to compare A objects.
You will have to implement the operator==.
Example of operator== (inline non-member function):
inline bool operator== (const A& left, const A& right){
return left.getX() == right.getX() && left.getY() == right.getY();
}
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.
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 searched a lot here and on other sites as well but i have not found something satisfying.
what i need is quite simple task - substantially to construct ORDER BY operator in c++. this means i have struct with a number of various data type members and i need a comparator for it with members and orderings configurable. here is my pseudocode idea:
comparator.add(&MyStruct::member1, std::less);
comparator.add(&MyStruct::member2, std::greater);
std::sort(my_vector.begin(), my_vector.end(), comparator);
and i get data sorted by member1 and if it is equal member2 decides, and so on.
i am not too good in stl and templates, but i can read and decipher some code and found this as very appropriate solution: https://stackoverflow.com/a/11167563
unfortunately in my work i have to use c++ builder with faulty 32bit compiler that refuses to compile this correct code. it does support almost nothing from c++11, it has boost 1.39 available.
does someone have any solution that could work for me with my resources available? thank you in advance
EDIT:
i got very specialised solutions with hard-written comparison operators which i am aware of and which do not work here too good. i missed this in my question. my struct has at least 15 members and as i wrote, i need to often change individual sort directions for members/columns (asc, desc). too, i need to often change set of sorted members, just like in order by operator in sql, for example. also i cannot use something like stable_sort as i am just writing comparator for something like OnCompare event of some class.
It's not too difficult. First, consider the "canonical"
ordering relationship:
struct Compare
{
bool operator()( C const& lhs, C const& rhs ) const
{
return lhs.a < rhs.a
|| ( !(rhs.a < lhs.a) && lsh.b < rhs.b )
|| ( !(rhs.a < lhs.a) && !(rhs.b < lhs.b) && lhs.c < rhs .c )
|| ...
}
};
Obviously, no one would actually write something like this, but
it corresponds exactly to the formal definition of what is
needed.
Of course, if we can imagine the data members as an array, we
could rewrite this as a loop, taking advantage of the previously
established !(rhs[i-1] < lsh[i-1] in each case:
struct Compare
{
bool operator()( C const& lhs, C const& rhs ) const
{
int i = 0;
while ( i != N && !(lhs[i] < rhs[i]) && !(rhs[i] < lhs[i]) ) {
++ i;
}
return i != N && lhs[i] < rhs[i];
}
};
Or, if all of the elements are fully ordered, so that == is
also defined on them, and we can assume that it corresponds to
the equivalence relationship established by the weak partial
ordering:
struct Compare
{
bool operator()( C const& lhs, C const& rhs ) const
{
int i = 0;
while ( i != N && !(lhs[i] == rhs[i]) ) {
++ i;
}
return i != N && lhs[i] < rhs[i];
}
};
All that remains is to somehow translate this into something
that can process an arbitrary ordering of elements of arbitrary
types. There's an old saying that the solution to every problem
is an additional level of indirection, and it applies here.
First, we need some means of handling the different types of
each element. Polymorphism seems appropriate (although
templates could be made to work if the order in which the
elements were evaluated were fixed at compile time):
struct CompareOneElementOfC
{
virtual bool isLessThan( C const& lhs, C const& rhs) const = 0;
virtual bool isEqual( C const& lhs, C const& rhs) const = 0;
};
template <typename T, T C::*ptr>
struct ConcreteCompareOneElementOfC : public CompareOneElementOfC
{
virtual bool isLessThan( C const& lhs, C const& rhs) const
{
return lhs.*ptr < rhs.*ptr;
}
virtual bool isEqual( C const& lhs, C const& rhs) const
{
return lhs.*ptr == rhs.*ptr;
}
};
Depending on the types of the elements, you may need to hand
write specific concrete instances. And if any of the elements
doesn't support total ordering, you will have to omit the
isEqual, and modify the following code accordingly.
Having got this far, we need exactly one static instance of each
concrete Compare:
ConcreteCompareOneElementOfC<int, &C::a> const c1;
ConcreteCompareOneElementOfC<double, &C::b> const c2;
// ...
Finally, put the addresses of these instances in a table:
CompareOneElementOfC const* const cmp[] = { &c1, &c2 ... };
You can have different tables for different orderings. If there
are only a few, define static tables for each, and be done with
it. If the orderings can be arbitrary, create the table on the
fly before each sort, in the desired order.
Finally:
class Compare
{
CompareOneElementOfC const* const* begin;
CompareOneElementOfC const* const* end;
public:
template< size_t N >
Compare( CompareOneElementOfC const* const (&cmp)[N] )
: begin( cmp )
, end( cmp + N )
{
}
bool
operator()( C const& lhs, C const& rhs ) const
{
auto current = begin;
while ( current != end && (*current)->isEqual( lhs, rhs ) ) {
++ current;
}
return current != end && (*current)->isLessThan( lhs, rhs );
}
}
(Please note that I haven't actually tested this code, so there
are probably typos and other errors. Still, the basic idea
should be there.)
I think just overloading operator < will work for you.
struct Struct {
int member1;
int member2;
bool operator<(const Struct& rhs) const {
if (member1 != rhs.member1)
return member1 < rhs.member1
else
return member2 > rhs.member2
}
};
This way whenever any 2 instances of Struct are compared, they will be compared by the comparison function defined in operator <.
So a simple std::sort(vec.begin(), vec.end()) will just work!
EDIT:
Otherwise you can always define a functor which can be used to compare each element. This is just a class with an overloaded operator () which is used for comparison.
class ComparisonClass {
public:
bool operator()(const Struct& lhs, const Struct& rhs) {
if (lhs.member1 != rhs.member1)
return lhs.member1 < rhs.member1
else
return lhs.member2 > rhs.member2
}
};
You can additionally define some member values of the ComparisonClass which define the order of comparisons.
Using it would be calling it like so std::sort(vec.begin(), vec.end(), ComparisonClass());
EDIT2:
Slightly more elaborate code -
class ComparisonClass {
public:
bool operator()(const Struct& lhs, const Struct& rhs) {
for(int i=0; i<m_comparisonOrder.size(); i++) {
int pos = m_comparisonOrder[i];
if (lhs[pos] != rhs[pos]) {
if (m_comparisonType[pos])
return lhs[pos] < rhs[pos];
else
return lhs[pos] > rhs[pos];
}
}
}
std::vector<int> m_comparisonOrder.
std::vector<bool> m_comparisonType;
};
Here I'm assuming that Struct has an operator [] which returns the appropriate member variable.
Why not have a specialized comparator function which first checks member1 and if equal then checks member2?
Like
bool comparator(const MyStruct& s1, const MyStruct& s2)
{
if (s1.member1 == s2.member1)
return s1.member2 > s2.member2;
else
return s1.member1 < s2.member1;
}
I am trying sort std::vector using algorithm::sort , But I am getting runtime error
Invalid operator <.
Following is my code.
struct Point {
double x_cord;
double y_cord;
int id;
Point(int d, double x, double y) {
x_cord = x;
y_cord = y;
id = d;
}
};
struct compareX {
bool operator ()(Point * left, Point* right) const {
if (left->x_cord < right->x_cord)
return true;
return true;
}
};
struct compareY {
bool operator ()(Point * left, Point* right) const {
if (left->y_cord <= right->y_cord) return true;
return true;
}
};
Here is now I am calling it after populating the values.
std::sort( posVector.begin(), posVector.end(), compareX());
Your comparison function always returns true!
Your comparison functions always seem to return true. Returning false occasionally might be a good idea. And (to be serious) comparing (x.y) coordinates is not as trivial as it might seem to be - you probably want to think about it a bit before implementing it.
If you are using std::vector<Point> then must be
struct compareX {
bool operator ()(const Point& left, const Point& right) const {
return left.x_cord < right.x_cord;
}
};
struct compareY {
bool operator ()(const Point& left, const Point& right) const {
return left->y_cord < right->y_cord;
}
};
The problems of your code are
comparison classes accept pointers instead of objects being sorted (if std::vector<Point> is sorted, i.e. not std::vector<Point*>). If you are sorting vector of pointers then it is fine.
comparison classes contain mistyping - always return true (as already mentioned)
compareY use <= instead of <. It is bad idea because standard algorithms (including sorting) expect less-semantic (not less_or_equal-semantic).
Overload the '<' operator for the Point class.