c++ How to search if struct element in vector is equal? - c++

A class named SparseMatrix has a vector of Nodes struct. I want to overload the += operator so that if the i and j members of a Node instance are the same then the value of that node will be added to This. How can i accomplish this using methods from the algorithm library?
I tried using find_if to pass to a function but it act only on one iterator:
class SparseMatrix
{
public:
SparseMatrix(int numRow,int numCol, std::vector<double> fill);
SparseMatrix(int numRow,int numCol);
SparseMatrix();
// assignment operations
bool operator==(const SparseMatrix &other) const;
bool operator!=(const SparseMatrix &other) const;
void operator-() const;
// compound operations
SparseMatrix& operator+=(const SparseMatrix &other);
SparseMatrix& operator*=(const SparseMatrix &other);
// binary operations
const SparseMatrix operator+(const SparseMatrix &other) const;
const SparseMatrix operator*(const SparseMatrix &other) const;
friend std::ostream& operator<<(std::ostream& output, const SparseMatrix sparseMatrix);
bool trace(double& result) const;
bool det(double& result) const;
SparseMatrix transpose();
~SparseMatrix(){};
protected:
vector<Node> _matrix;
int _numCol, _numRow;
};
typedef struct Node {
int i;
int j;
double value;
static bool samePosition(const Node& other)
{
return ((i == other.i) && (j == other.j));
}
} Node;
SparseMatrix& SparseMatrix::operator+=(const SparseMatrix &other)
{
vector<Node>::iterator itThis;
for (vector<Node>::iterator itOther = other._matrix.begin(); itOther != other._matrix.end(); ++itOther)
{
// find if already exists a value in the same matrix position
itThis = find_if(_matrix.begin(), _matrix.end(), Node::samePosition);
// if exists add value to position, else instantiate new Node with value & position
}
return *this;
}
Basically, I want Node::samePosition() to pass two parameters - the current iterator passed by find_if and itOther so it can check if they are equal.
EDIT: I have separated the samePosition function and now want to pass to it two parameters using find_if:
typedef struct Node {
int i;
int j;
double value;
} Node;
static bool SparseMatrix::samePosition(const Node& first, const Node& other)
{
return ((first.i == other.i) && (first.j == other.j));
}
SparseMatrix& SparseMatrix::operator+=(const SparseMatrix &other)
{
vector<Node>::iterator itThis;
for (vector<Node>::iterator itOther = other._matrix.begin(); itOther != other._matrix.end(); ++itOther)
{
itThis = find_if(_matrix.begin(), _matrix.end(), SparseMatrix::samePosition("call what here?",itOther));
}
return *this;
}

You are trying to use
static bool SparseMatrix::samePosition(const Node& first, const Node& other)
{
return ((first.i == other.i) && (first.j == other.j));
}
which is a standalone function. All its data has to be supplied by the caller, but find_if knows nothing about the Node you want to compare against the entire list.
Instead you should use a functor, which is an object that can hold some data, and also implements operator()() so that it can be called like a function.
struct position_finder
{
const Node needle;
position_finder( const Node& sought ) : needle(sought) {}
bool operator()( const Node& haystack ) const
{
return ((needle.i == haystack.i) && (needle.j == haystack.j));
// or return samePosition(needle, haystack)
}
};
and then you pass the sought Node when constructing the functor, so it gets stored for later use:
itThis = find_if(_matrix.begin(), _matrix.end(), position_finder(*itOther));
C++11 makes this all a whole lot easier, since a lambda will cause the compiler to generate that struct for you:
itThis = find_if(_matrix.begin(), _matrix.end(), [itOther](Node& arg){ return ((itOther->i == arg.i) && (itOther->j == arg.j)); });

Related

Templated operator ==

I have what is essentially class containing a std::map where the values are shared_ptrs wrapping a container which holds different types. Skeleton code follows:
// Just a basic example class
class MyClass {
public:
explicit MyClass(int i) : mI(i) {}
bool operator==(const MyClass& rhs) { return mI == rhs.mI; }
private:
int mI;
};
// A class into which key value pairs can be added where the value
// can be of a different type.
class MultipleTypeMap {
public:
template <typename T>
void AddObject(const std::string& key, const T object) {
auto ptr = make_shared<B<MyClass>>(std::move(object));
mSharedPtrMap.insert(pair<string, shared_ptr<A>>("key", ptr));
}
// ...
private:
class A {
public:
virtual ~A() = default;
};
template<typename T>
class B : public A {
public:
explicit B(const T& t) : item(t) {}
const T item;
};
map<string, shared_ptr<A>> mSharedPtrMap;
};
int main() {
MyClass m(1);
MultipleTypeMap multiMap;
multiMap.AddObject("test", m);
MyClass n(1);
MultipleTypeMap multiMap2;
multiMap2.AddObject("test", n);
if (multiMap == multiMap2) {
cout << "Equal" << endl;
}
return 0;
}
How should a generic == operator of MultipleTypeMap be written so that it compares the contents of mSharedPtrMap by checking that both the lhs and rhs objects have the same number of keys, the same keys and the same objects where same means that the == operator of the keys / objects evaluates to true?
If you type erase (and later on don't know which type you previously stored), then all the functionality must be provided by the base class interface. So, we need a virtual operator== in A that is implemented in each B.
Here is an implementation:
class MultipleTypeMap {
public:
template <typename T>
void AddObject(const std::string& key, T object) {
auto ptr = std::make_unique<B<T>>(std::move(object));
mMap.emplace(key, std::move(ptr));
}
// ...
bool operator==(const MultipleTypeMap& other) const
{
// Sizes must be equal.
if (mMap.size() != other.mMap.size())
return false;
// Sizes are equal, check keys and values in order.
auto itOther = other.mMap.begin();
for (auto it = mMap.begin(); it != mMap.end(); ++it, ++itOther)
{
if (it->first != itOther->first)
return false;
if (*it->second != *itOther->second)
return false;
}
// No differences found.
return true;
}
bool operator!=(const MultipleTypeMap& rhs) const { return !(*this == rhs); }
private:
class A {
public:
virtual ~A() = default;
virtual bool operator==(const A& other) const = 0;
bool operator!=(const A& other) const { return !(*this == other); }
};
template<typename T>
class B : public A
{
public:
explicit B(const T& t) : item(t) {}
bool operator==(const A& other) const override
{
const B<T>* otherB = dynamic_cast<const B<T>*>(&other);
// If the cast fails, types are different.
if (!otherB)
return false;
// Note: The above is probably slow, consider storing (on construction)
// and checking typeids instead.
// Check item equality.
return item == otherB->item;
}
const T item;
};
std::map<std::string, std::unique_ptr<A>> mMap;
};
Demo with tests
Note: I didn't fix every inconsistency in the original code. (Do you want to move or copy-construct your T? Why store const objects when your MyClass comparison operator is not const?)

How do you overload the '<' operator to compare between objects of the same class?

Right now I have a class item
class Item{
public:
short p; //profit
short w; //weight
bool *x; //pointer to original solution variable
void set_values (short p, short w, bool *x);
};
and I need to compare two different instances so that it checks the values of each one and returns either true/false
if (Item a < Item b){
//do something
}
How can I do that? I've been reading cppreference but I don't really understand how to do it.
Very simply,
bool Item::operator<(const Item& other) const {
// Compare profits
return this->p < other.p;
}
To compare both the left hand side p and w with the right hand side p and w use the following code:
class MyClass
{
public:
short p;
short w;
friend bool operator<(const MyClass& lhs, const MyClass& rhs)
{
return lhs.p < rhs.p && lhs.w < rhs.w;
}
};
For example, if you want to compare p, the code should look like this:
class Item {
private:
...
public:
friend bool operator < (const Item& lhs, const Item& rhs) {
return lhs.p < rhs.p;
}
};

Overload operator < in super class using pure virtual methods

I have a hierarchy of Figure as base class and several sub classes Circle, Square, ecc. I want to overload < operator in Figure to sort Figures by eg. Surface which is implemented in base classes.
This is my code:
//Figure.hpp
class Figure
{
public:
virtual float surface() const = 0;
virtual float perimeter() const = 0;
friend bool operator<(const Figure& lhs, const Figure& rhs);
friend bool operator>=(const Figure& lhs, const Figure& rhs);
}
//Figure.cpp
bool operator<(const Figure& lhs, const Figure& rhs)
{
return lhs.surface() < rhs.surface();
}
bool operator>=(const Figure& lhs, const Figure& rhs)
{
return lhs.surface() >= rhs.surface();
}
//Square.hpp
class Square : public Figure{
public:
Square(float size);
float surface() const{
return mSize * mSize;
};
float perimeter()const{
return mSize * 4;
}
private:
float mSize;
};
Problem is I get an error at runtime:
libc++abi.dylib: Pure virtual function called!
at lhs.surface().
I call the < operator in a LinkedList with Template:
template <typename T>
void List<T>::insertNewNode(T& dataIn)
{
if(isEmpty())
{
insertBegin(dataIn);
}else //otherwise
{
if(dataIn < *startPtr->data)
{
insertBegin(dataIn);
}
else if(dataIn >= *endPtr->data) /
{
insertEnd(dataIn);
}
else
{
//...
}
}
}
//main.cpp
List<Figure> *list = new List<Figure>();
Figure *square = new Square(46);
list->insertNewNode(*square);
EDIT
https://github.com/sanandrea/GenericLinkedList
Is this feasible or I am doing everything wrong?
The problem is both Object Slicing and undefined behavior.
You insert values via
void List<T>::insertNewNode(T& dataIn)
which is OK. Since you pass it by reference the polymorphism will be kept. However, when you later call insertBegin or insertEnd to actually create the node you pass it by T:
void List<T>::insertBegin(T dataIn)
Here dataIn have lost the polymorphism due to Object Slicing. You also have undefined behavior when you store a pointer to the parameter in the newly created node:
ListNode<T> * newPtr = new ListNode<T>(&dataIn); //creates new node
Note that &dataIn is a pointer to the parameter of insertBegin, not a pointer to the dataIn that was passed in insertNewNode(T& dataIn).
You also have Object Slicing in your node: T ListNode<T>::getData() //returns data stored in node.

error C2678 in using template

I'm defining a priority queue and use it on a self-defined struct but I get this error and I don't know how to fix it.
This is my error:
error C2678: binary '<' : no operator found which takes a left-hand operand
of type 'const Location' (or there is no acceptable conversion)
my struct Location
struct Location
{
int x, y, value;
Location(int a, int b);
bool operator == (const Location& other);
bool operator < (const Location& other);
};
Location:: Location(int a, int b) {
x = a;
y = b;
value = 0;
}
bool Location:: operator == (const Location& other) {
return (x == other.x && y == other.y);
}
bool Location:: operator < (const Location& other) {
return value > other.value;
}
Here's my priority queue
template<typename T>
struct my_priority_queue {
priority_queue<T, vector<T>, greater<T>> elements;
bool empty()
{
return elements.empty();
}
void push(T item)
{
elements.emplace(item);
}
T pop()
{
T best = elements.top();
elements.pop();
return best;
}
};
The main function
int main() {
Location a(0, 0);
Location b(1, 2);
Location c(3, 0);
my_priority_queue<Location> my_pq;
my_pq.push(a);
}
It's as it says.
Your operator cannot take a const Location on the LHS, because it is not a const function.
bool operator == (const Location& other) const;
bool operator < (const Location& other) const;
// ^^^^^^

C++ - no operator found

I have a vector filled with values of a custom type and the find() algorithm is complaining that it cannot find a suitable == operator for the value comparison. I've implemented it like this:
bool Ship::operator==(const Ship& source) {
return (_type == source._type &&
_damagedSquares == source._damagedSquares &&
_orientation == source._orientation && _state == source._state);
}
I've also tried the "friend" method approach but that doesn't work either.
The class itself is structured like this:
class Ship {
private:
ShipType _type;
int _damagedSquares;
ShipOrientation _orientation;
ShipState _state;
public:
Ship();
Ship(ShipType type);
~Ship();
bool operator==(const Ship& source);
};
What am I doing wrong here?
Additional info:
std::vector<Ship> remainingShips;
MultiArray& squares = opponentGridCopy.GetSquares();
for (RowIterator rowIterator = squares.begin(); rowIterator != squares.end();
++rowIterator) {
for (ColumnIterator columnIterator = rowIterator->begin();
columnIterator != rowIterator->end(); ++columnIterator) {
Square* current = &(*columnIterator);
SquareState currentState = current->GetState();
if (currentState != SquareState::Hit)
current->SetState(SquareState::Vacant);
Ship* potentialShip = current->GetOwner();
if (potentialShip != nullptr) {
int damagedSquares = potentialShip->GetDamagedSquares();
if (!damagedSquares) {
current->SetState(SquareState::Populated);
break;
}
if (remainingShips.empty() ||
std::find(remainingShips.begin(), remainingShips.end(),
potentialShip) ==
remainingShips.end()) // should be *potentialShip
remainingShips.push_back(*potentialShip);
}
}
}
return remainingShips;
I was passing a pointer as a compare value...
Simply dereferenced it and find() works now.
Declare your comparison operator like so:
bool Ship::operator==( const Ship &source ) const
Note the trailing const.
Ship* potentialShip = ...
std::find(remainingShips.begin(), remainingShips.end(), potentialShip)
you're trying to find a pointer while the vector where the search is performed is defined as
std::vector<Ship> remainingShips;
you're comparing a pointer with a Ship object and thus your comparison is wrong
bool Ship::operator==(const Ship& source) // Accepts a Ship reference, not a pointer
To fix it either dereference the pointer or change your comparison function.
Your
bool operator==(const Ship& source);
Should be const as well, namely
bool operator==(const Ship& source) const;
But actually, I prefer to have symmetric operators, not as member methods.
Consider:
Class Ship
{
private:
ShipType _type;
int _damagedSquares;
ShipOrientation _orientation;
ShipState _state;
public:
Ship();
Ship(ShipType type);
~Ship();
static bool eq(const Ship& s0, const Ship& s1)
{
return (s0._type == s1._type &&
s0.damagedSquares == s1._damagedSquares &&
s0._orientation == s1._orientation &&
s0._state == s1._state);
}
};
inline bool operator==(const Ship& s0, const Ship& s1)
{
return Ship::eq(s0, s1);
}