Passing set to templatised function - c++

Here's my complete working code
class Point2D
{
protected:
int x, y;
public:
Point2D(int x_, int y_) : x(x_), y(y_)
{
}
int getX() const
{
return x;
}
int getY() const
{
return y;
}
bool operator< (const Point2D & pointObj) const
{
if(x == pointObj.getX() && y == pointObj.getY())
return false;
return pointObj.getX() == x ? true : x < pointObj.getX();
}
};
template<typename T, typename U>
void printSet(const set<T>& setToPrint)
{
set<T, U> pSet;
for(typename set<T>::iterator it = setToPrint.begin(); it != setToPrint.end(); it++)
{
pSet.insert(*it);
}
for(typename set<T,U>::iterator it = pSet.begin(); it != pSet.end(); it++)
{
//here print the element
}
}
int main()
{
set<Point2D> setP2;
setP2.insert(Point2D(1,3));
setP2.insert(Point2D(3,2));
int i = 1;
if(i==1)
{
printSet<Point2D, std::less<Point2D > >(setP2);
i++;
}
if(i==2)
{
printSet<Point2D, std::greater<Point2D > >(setP2);
}
}
It produces a bunch of errors from template code, but I think below is the primary one
/usr/include/c++/5/bits/stl_function.h:377:20: error: no match for ‘operator>’ (operand types are ‘const Point2D’ and ‘const Point2D’)
/usr/include/c++/5/bits/stl_function.h:377:20: note: ‘const Point2D’ is not derived from ‘const std::pair<_T1, _T2>’
What is wrong with the code?

In order to be able to create std::set<Point2D, std::greater<Point2D>>, you need to implement operator> between two objects of type Point2D.
Add a member funtion similar to operator< in the class to resolve the problem.
Suggestion for improvement
The operator< function can be simplified to user fewer compare operations.
bool operator< (const Point2D & pointObj) const
{
if ( x != pointObj.x )
{
return ( x < pointObj.x );
}
return ( y < pointObj.y );
}
The operato> function can be similarly implemented as:
bool operator> (const Point2D & pointObj) const
{
if ( x != pointObj.x )
{
return ( x > pointObj.x );
}
return ( y > pointObj.y );
}

You have implemented the < operator, not the >. C++ is pretty particular about that kind of thing. Implement operator> and you should be all set.
You can do that in terms of operator< if you like:
bool operator> (const Point2D & pointObj) const
{
if(x == pointObj.getX() && y == pointObj.getY())
return false;
return pointObj < this;
}
You can see more examples here.

Related

comparing == operator for (struct &a, struct &b) vs (const struct &a, const struct &b)

I have defined a struct class called Point in my header file as follows -
namespace global_planner {
class GlobalPlanner : public nav_core::BaseGlobalPlanner {
struct Point {
__uint32_t x, y;
bool operator==(const Point &p1 ) {
return ((p1.x == x) && (p1.y == y));
}
bool operator<(const Point &p1 ) const {
return ((p1.x < x) || (p1.x == x && p1.y < y) ) ;
}
};
public:
///
private:
////
};
};
In my source file (named global_planner.cpp), I have a function named generate_straight_path defined as follows -
bool GlobalPlanner::generate_straight_path(const Point &p1, const Point &p2){
if(costmap_ros_->getCost(p1.x, p1.y) == costmap_2d::LETHAL_OBSTACLE) {
cout << "Point p1 is on obstacle!" << endl;
return false;
}
if(costmap_ros_->getCost(p2.x, p2.y) == costmap_2d::LETHAL_OBSTACLE) {
cout << "Point p2 is on obstacle!" << endl;
return false;
}
if(p1 == p2) {return 1;}
if(p1.x == p2.x){}
if(p1.y == p2.y){}
}
When I compile global_planner.cpp, I am getting the following error -
/home/skpro19/catkin_ws/src/my_global_planner/src/global_planner.cpp: In member function ‘bool global_planner::GlobalPlanner::generate_straight_path(const global_planner::GlobalPlanner::Point&, const global_planner::GlobalPlanner::Point&)’:
/home/skpro19/catkin_ws/src/my_global_planner/src/global_planner.cpp:150:11: error: no match for ‘operator==’ (operand types are ‘const global_planner::GlobalPlanner::Point’ and ‘const global_planner::GlobalPlanner::Point’)
if(p1 == p2) {return 1;}
The error disappears if I change the definition of generate_straight_path from generate_straight_path(const Point &p1, const Point &p2) to generate_straight_path(Point &p1, Point &p2).
Why is this happening?
Your equality operator overload is a member function, but not marked const:
bool operator==(const Point &p1 ) { return ((p1.x == x) && (p1.y == y)); }
When you turn it into a const member function, this should work as expected:
bool operator==(const Point &p1 ) const { return ((p1.x == x) && (p1.y == y)); }
It's a bit blurry through the operator, but when you look at it this way:
bool GlobalPlanner::generate_straight_path(const Point &p1, const Point &p2){
// ...
if (p1.operator==(p2)) /* ... */ ;
}
which is the more verbose way to call an member operator overload, you can see that this operator== must be const because the function argument const Point& p1 is const itself.
It is only by coincidence that you can fix it by removing a const. In fact you need to add one here:
bool operator==(const Point &p1 ) const { return ((p1.x == x) && (p1.y == y)); }
// ^^^
Otherwise you can only call operator== with a non-const left hand operand.

class Edge List c++

I'm trying to make the Edge List class on c++.
When I compile the code, I get a lot of errors, but I can not understand, what do I wrong?
struct vertex
{
double x,y;
};
class EdgeList
{
private:
std::map<vertex, vector<vertex>> graph_container;
public:
void add_vertex(const vertex& v) { //add a vertex to the map
graph_container.insert(pair<vertex,vector<vertex> >(v, vector<vertex>()));
}
//*
void add_edge(const vertex& v, const vertex& u) { //look up vertex in map
auto it = graph_container.find(v);
if (it != graph_container.end())
*it.push_back(u);
}
//*/
};
The first error is
64-w64-mingw32/include/c++/iostream:39,
from EarTr.cpp:1:
C:/mingw-w64/x86_64-5.2.0-win32-seh-rt_v4-rev0/mingw64/x86_64-w64-mingw32/includ
e/c++/bits/stl_function.h:387:20: note: 'const vertex' is not derived from 'co
nst std::__cxx11::basic_string<_CharT, _Traits, _Alloc>'
{ return __x < __y; }
I've added 2 functions to the struct
bool operator==(const vertex &o)const {
return x == o.x && y == o.y;
}
bool operator<(const vertex &o) const{
return x < o.x || (x == o.x && y < o.y);
}
So, now the map can work with my type of data.
Also I use
it->second.push_back(u);
instead of
*it.push_back(u);

How to overload operator for a set of sets of object

I need to know how to overload the operator = != and < so I could work with set<set<object> >
I have my class:
class pr{
private:
set<set<e> > pr_;
public:
pr();
~pr();
void set_pr(set<e> a);
pr& operator=(const pr& a) const;
bool operator!=(const pr& a) const;
bool operator<(const pr& a) const;
};
So if I have a set like this: {{1,2,3},{4,5}} where the numbers are objects.
I would like to do operations with the sets in other class like this:
void otherclass::myfunction(){
pr prt; //I create the objects
pr prt_old;
set<e> C1; //I create the subset and fill
set<e> C2;
//C1 and C2 filled here
prt.set_pr(C1); //Insert the set<e> into set<set<e>>
prt.set_pr(C2); //It will fail because i dont know how to compare set<e> < <set<e>
while(prt != prt_old){
prt_old = prt ;
prt = create(prt_old);
}
//...
I tried to overload doing this:
pr& pr::operator=(const pr& a) const{
this->clear();
for(set<set<e> >::iterator it =a.begin();it!=a.end();it++){
for(set<e>::iterator j = it->begin(); j != it->end();j++){
this->set_pr(*j);
}
}
return *this;
}
bool pr::operator!=(const pr& a) const{
if(this->size() != a.size()){
return 1;
}
//Now i don't know how to continue for check if for example
// i had {{1,2},{3,4}} and {{1},{2}}
//this two set have same size but they are differnt
//How could i just iterate through the two sets at same time
// and check if subset have too same size or if the objects inside the subset are equal
//Also i need the operator < to insert a set<e> into a set<set<e> > but how??
//Note: class 'e' has already defined the "operator<" for when I insert objects in the set<e>
//And i order them by a function that return an integrer
To test if one set is contained in the other, you iterate over each member of the first set, and test if it exists in the second set.
bool operator<(const pr& a) const {
for (auto _set : _data) {
if (a._data.find(_set) == a._data.end())
return false;
}
return true;
}
To test if two sets are identical, you test their size is equal, and that one is contained in the other
bool operator==(const pr& a) const {
return _data.size() == a._data.size() && *this < a;
}
But notice that there is no need to define an operator==, because the default one defined by std::set is fine.
Here is a full functioning program:
#include <iostream>
#include <set>
using namespace std;
template <class e>
class pr {
private:
set<set<e> > _data;
public:
void insert(set<e> a) { _data.insert(a); }
bool operator==(const pr& a) const {
return _data.size() == a._data.size() && *this < a;
}
bool operator!=(const pr& a) const { return !(*this == a); }
bool operator<(const pr& a) const {
for (auto _set : _data) {
if (a._data.find(_set) == a._data.end())
return false;
}
return true;
}
};
int main()
{
pr<int> a,b,c;
a.insert(set<int>({ 1 }));
b.insert(set<int>({ 1 }));
b.insert(set<int>({ 1, 2 }));
c.insert(set<int>({ 1, 2 }));
c.insert(set<int>({ 1 }));
std::cout << ((a<b) ? "a<b\n" : "NOT a<b\n");
std::cout << ((b<a) ? "b<a\n" : "NOT b<a\n");
std::cout << ((a==c) ? "a==c\n" : "NOT a==c\n");
std::cout << ((b==c) ? "b==c\n" : "NOT b==c\n");
std::cout << ((a==b) ? "a==b\n" : "NOT a==b\n");
return 0;
}

operator <= overloading for 2 classes and converting ctor

I have a little problem, which the Visual Studio compiler don't seem to be bothered by, but do in eclipse and g++.
I have 2 classes, Card and CardDeck. I do have the operator <= for 2 Carddecks as parameters and do not for 2 cards. I have a converting ctor, which converts Card to a Deck.
So the problem is when I do:
card1 <= card2
Which does work fine in visual, as it converts the left part to deck, then converts the right and then does the comparing.
In g++ it says:
no match for 'operator<=' (operand types are 'Card' and 'Card')
But there shouldn't be one. as I said I want the convert ctor would convet both sides and do the compare?
Any explanation and solution for this ?
Edit(the operator and ctor declaration and code):
CardDeck(const Card&);
friend bool operator<=(const CardDeck&, const CardDeck&);
CardDeck::CardDeck(const Card& card){
_Deck.push_back(card);
}
Here's a quick&dirty of what I think you are trying to do:
#include <iostream>
struct Element
{
int x;
Element() :x(0) {}
virtual ~Element() {}
};
struct Container
{
Element elems[10];
int n;
Container() { n=0; }
Container(const Element &e) { elems[0]=e; n=1; }
virtual ~Container() {}
friend bool operator<=(const Container &l, const Container &r);
};
bool operator<=(const Container &l, const Container &r)
{
if (l.n<=r.n) { std::cout << "less/equ\n"; return true; }
else { std::cout << "greater\n"; return false; }
}
int main(int argc, const char *argv[])
{
//Container container;
Element a, b;
if (a<=b) std::cout << "okay\n"; else std::cout << "fail\n";
return 0;
}
It works fine with gcc.
Deck(card1) <= Deck(card2)
Make operator<= (operand types are 'Card' and 'Card') override cause you use(mean) that in card1 <= card2 expression. Your code have architecture errors.
Update:
struct Card
{
bool operator<( const Card& right ) const;
};
struct Deck
{
std::vector<Card> m_arr;
Deck() = default;
Deck( const Card& conversion )
{
m_arr.push_back( conversion );
}
bool operator<( const Deck& right ) const;
};
bool Card::operator<( const Card& right ) const
{
return false;
}
bool Deck::operator<( const Deck& right ) const
{
bool result = false;
if(m_arr.size() < right.m_arr.size())
{
result = true;
}
else if(!m_arr.empty() && m_arr.size() == right.m_arr.size() )
{
result = true;
std::vector<Card>::const_iterator it = right.m_arr.begin();
std::vector<Card>::const_iterator it2 = m_arr.begin();
for(; it2 != m_arr.end(); ++it, ++it2 )
{
if((*it) < (*it2))
{
result = false;
break;
}
}
}
return result;
}

Create Iterator to C++ container that returns a std::pair

I'm trying to implement a container in C++ that uses a flat array to store the data but iterates over that data in pairs. Now I could easily change the implementation such that the container holds a vector of std::pair however I want to iterate through pairs starting at element 0 or at element 1.
To illustrate what I want to achieve, if my underlying array looks like:
1,2,3,4,5,6,7,8
I want to define two iterators, one which returns the pairs:
(1,2), (3,4), (5,6), (7,8)
and the second iterator to return the pairs:
(2,3), (4,5), (6,7)
is this possible to do while still allowing the elements of the iterator to be references of the underlying array?
It is possible to write your own iterator, which iterates over the elements. The following question shows some explanations on how that is done:
Custom Iterator in C++.
You can then return the desired values as std::pair and iterate to the next element-pair (by incrementing the counter by 2).
Boost library has got Iterator Adaptor that allows you to wrap other iterator types and change or adapt their functionality. Here's how you could use it for your purpose:
#include <boost/iterator/iterator_adaptor.hpp>
#include <vector>
struct iterator :
public boost::iterator_adaptor<
iterator, // the name of our class, see docs for details
std::vector<int>::iterator, // underlying base iterator
std::pair<int&, int&>, // our value type
boost::forward_traversal_tag // the category you wish to give it
>
{
// need this to convert from vector::iterator to ours
explicit iterator(std::vector<int>::iterator i)
: iterator::iterator_adaptor_(i) {}
value_type operator*()
{
return value_type(
*base_reference(),
*(base_reference()+1)
);
}
};
Example of usage:
std::vector<int> v {1,2,3,4};
iterator it(v.begin());
++it;
(*it).first = 0; // TODO: operator->
(*it).second = 0;
for (int i : v) std::cout << i << ' '; // prints 1 0 0 4
You'll also need to override comparison to properly handle end condition, etc. Hope that helps.
Just thought I'd put in what I actually used in my code. I didn't want to use boost as suggested by #jrok but the type std::pair<int&, int&> in their answer gave me a hint of what was required.
Below is the class that I constructed which uses two iterators. A RepeatIterator that returns pairs starting on even indexes in the underlying data, and a SpacerIterator that returns pairs starting on odd indexes.
class RepeatArray {
typedef std::vector<int> storage_t;
public:
class RepeatIterator {
public:
typedef RepeatIterator self_t;
typedef int value_t;
typedef int& reference_t;
typedef int* pointer_t;
typedef std::pair<reference_t, reference_t> return_t;
RepeatIterator(storage_t::iterator input) : current_pos(input){}
return_t operator *() {
return return_t(*(current_pos), *(current_pos + 1 ));
}
self_t operator++() { self_t i = *this; current_pos += 2; return i; }
self_t operator++(int junk) { current_pos+=2; return *this; }
bool operator==(const self_t& rhs) { return current_pos == rhs.current_pos; }
bool operator!=(const self_t& rhs) { return current_pos != rhs.current_pos; }
bool operator<(const self_t& rhs) { return current_pos < rhs.current_pos; }
bool operator<=(const self_t& rhs) { return current_pos <= rhs.current_pos; }
bool operator>(const self_t& rhs) { return current_pos > rhs.current_pos; }
bool operator>=(const self_t& rhs) { return current_pos >= rhs.current_pos; }
private:
storage_t::iterator current_pos;
};
class SpacerIterator {
public:
typedef SpacerIterator self_t;
typedef int value_t;
typedef int& reference_t;
typedef int* pointer_t;
typedef std::pair<reference_t, reference_t> return_t;
SpacerIterator(storage_t::iterator input) : current_pos(input){}
return_t operator *() {
return return_t(*(current_pos), *(current_pos + 1 ));
}
self_t operator++() { self_t i = *this; current_pos += 2; return i; }
self_t operator++(int junk) { current_pos+=2; return *this; }
bool operator==(const self_t& rhs) { return current_pos == rhs.current_pos; }
bool operator!=(const self_t& rhs) { return current_pos != rhs.current_pos; }
bool operator<(const self_t& rhs) { return current_pos < rhs.current_pos; }
bool operator<=(const self_t& rhs) { return current_pos <= rhs.current_pos; }
bool operator>(const self_t& rhs) { return current_pos > rhs.current_pos; }
bool operator>=(const self_t& rhs) { return current_pos >= rhs.current_pos; }
private:
storage_t::iterator current_pos;
};
void add(int start, int end) {
positions.push_back(start);
positions.push_back(end);
}
void dump() {
for (auto i : positions) {
std::cout <<i<<",";
}
std::cout <<std::endl;
}
RepeatIterator repeatBegin(){return RepeatIterator(positions.begin());}
RepeatIterator repeatEnd(){return RepeatIterator(positions.end());}
SpacerIterator spacerBegin(){return SpacerIterator(positions.begin() + 1);}
SpacerIterator spacerEnd(){return SpacerIterator(positions.end() - 1);}
protected:
storage_t positions;
};
And then the tesing program compiled using clang++ -std=c++0x -o testRepeatArray RepeatArray.cpp
int main() {
RepeatArray r = RepeatArray();
r.add(1,3);
r.add(7,12);
std::cout<<"original:"<<std::endl;
r.dump();
std::cout << "Testing Repeat iterator:"<<std::endl;
for (RepeatArray::RepeatIterator it2 = r.repeatBegin(); it2 != r.repeatEnd(); ++it2) {
std::cout << (*it2).first <<","<< (*it2).second << std::endl;
}
std::cout << "Testing Spacer iterator:"<<std::endl;
for (RepeatArray::SpacerIterator it3 = r.spacerBegin(); it3 != r.spacerEnd(); ++it3) {
std::cout << (*it3).first <<","<< (*it3).second << std::endl;
}
std::cout<<"Testing modification:"<<std::endl;
RepeatArray::RepeatIterator it = r.repeatBegin();
(*it).first = 0;
(*it).second = 123;
r.dump();
return 0;
}