C++ - no operator found - c++

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);
}

Related

operator overloading abstract class

There is an Student abstract class, and two derived class Grad and Undergrad; and I want to overload operator in several ways.
student.h
class Student {
protected:
string Name;
int Stu_num;
public:
virtual void print() = 0;
bool operator==(const Student& x) const;
// constructor...
}
class Grad_Student : public Student {
private:
string Lab;
public:
void print();
bool operator==(const Grad_Student& x) const;
// constructor...
}
class Undergrad_Student : public Student {
private:
string Major;
public:
void print();
bool operator==(const Undergrad_Student& x) const;
// constructor...
}
student.cpp
bool Student::operator==(const Student& x) const {
if (this->Name == x.Name && this->Stu_num == x.Stu_num) {
if (typeid(*this).name() != typeid(x).name()) {
return false;
}
else if (!(strcmp(typeid(*this).name(), "12Grad_Student"))) {
return *dynamic_cast<const Grad_Student *>(this) == *dynamic_cast<const Grad_Student *>(&x);
}
else {
return *dynamic_cast<const Undergrad_Student *>(this) == *dynamic_cast<const Undergrad_Student *>(&x);
}
}
else {
return false;
}
}
bool Grad_Student::operator==(const Grad_Student& x) const {
return this->Lab == x.Lab;
}
bool Undergrad_Student::operator==(const Undergrad_Student& x) const {
return this->Major== x.Major;
}
To find student object in Student *students[300]
this operation == overloading works and doen't have problem,
but I want to implement overloading in different way using below.
How can I implement this function??
bool operator==(const Student& x, const Student& y)
{
// do comparison...
}
While that may appear to work, type_info::name() is
implementation-dependent,
not guaranteed to be unique between different types,
not guaranteed to be the same between different executions of the same program.
Comparing type_infos directly is reliable though, so you could do things like if (typeid(*this) == typeid(Grad_Student)) and it would work as expected.
However, polymorphism already exists, so you don't need to implement it yourself, and you can avoid a lot of trouble (and overhead) by dispatching to a virtual function instead of enumerating subclasses.
Something like this:
class Student {
public:
bool equals(const Student& s) const
{
return Name == s.Name
&& Stu_num == s.Stu_num
&& typeid(*this) == typeid(s)
&& equals_internal(s);
}
private:
virtual bool equals_internal(const Student& s) const = 0;
string Name;
int Stu_num;
};
bool operator==(const Student& lhs, const Student& rhs)
{
return lhs.equals(rhs);
}
class Grad_Student : public Student {
private:
string Lab;
bool equals_internal(const Student& s) const override
{
return Lab == static_cast<const Grad_Student&>(s).Lab;
}
};
class Undergrad_Student : public Student {
private:
string Major;
bool equals_internal(const Student& s) const override
{
return Major == static_cast<const Undergrad_Student&>(s).Major;
}
};
Note that the static_casts are safe, since Student has already established the type equality.

How do I establish a comparator for a set c++

I have a set, and for this set, I need two different comparators. For example, for a set frontier I need to sort by cost, but I have another set board which needs to be sorted by coordinates. I know you can define a comparator for each set using the comparator as the second argument, but I have tried this and it gave me an error.
The code I tried to use:
struct tile {
int id;
int xCord;
int yCord;
int cost;
...
bool operator<(const tile& Rhs) const {
if (cost < Rhs.cost) {
return true;
}
else if (cost < Rhs.cost) {
return false;
}
else {
if (id < Rhs.id) {
return true;
}
else
return false;
}
}
...
};
The other struct that I'm using for the comparator (I know this is most likely incorrect, which is why I'm asking for help.):
struct costComp {
int id;
int xCord;
int yCord;
int cost;
costComp() {}
costComp(int a, int b, int c, int d = 0) :
id(a),
xCord(b),
yCord(c),
cost(d) {}
bool operator<( const tile& Rhs) const {
if (xCord < Rhs.xCord)
return true;
else if (xCord < Rhs.xCord)
return false;
else {
if (yCord < Rhs.yCord)
return true;
else if (yCord < Rhs.yCord)
return false;
else
return false;
}
}
};
Then, I define the set as:
set<tile,costComp> startBoard;
The error I got:
c2064: term does not evaluate to a function taking 2 arguments
Any help is greatly appreciated.
the Compare parameter in std::set is intended to be some callable type that can be invoked with (const tile&, const tile&). This means you can use a functor that overloads operator(), for example, like this:
struct Comp {
bool operator()(const tile& lhs, const tile& rhs) const {
if (lhs.id < rhs.id) return true;
if (lhs.id > rhs.id) return false;
if (lhs.xCord < rhs.xCord) return true;
if (lhs.xCord > rhs.xCord) return false;
if (lhs.yCord < rhs.yCord) return true;
if (lhs.yCord > rhs.yCord) return false;
return lhs.cost < rhs.cost;
}
// or maybe, if this logic already exists:
bool operator()(const tile& lhs, const tile& rhs) const {
return lhs < rhs; // invoke tile::operator<(const tile&)
}
};
...
std::set<tile, Comp> myset;
This way, the comparator struct doesn't need to keep track of the details of any one tile object, and the redundant members of costComp can be removed.
If you want the comparator to be configurable, you can add members to the Comp struct definition and initialize them in a constructor call when you instantiate the set:
struct Comp {
Comp(bool use_cost = false /* default behavior */) : m_use_cost(use_cost) {}
bool operator()(const tile& lhs, const tile& rhs) const {
if (m_use_cost){
return lhs.cost < rhs.cost;
} else {
...
}
}
private:
const bool m_use_cost;
};
...
// default comparison, won't use cost
std::set<tile, Comp> setA;
// specify custom behaviour
std::set<tile, Comp> setB {Comp{true /* right here */}};
Obviously, the configurability is not limited to one or more bools. It might make sense to have some enum with values like SortByCost, SortByXcoord. Alternatively, you could have a separate functor struct that does each, but this means that sets with different comparators will have different types and will not be inter-copyable or moveable.

Why is this assert failing?

The assert in main.cpp is failing, and I don't understand why.
Here is string.hpp
class String
{
private:
int len;
char* str;
public:
String(char const* s); // C-string constructor
~String() {delete str;}; // destructor
char* const getString(); //get string for printing
};
inline bool operator==(String lhs, String rhs)
{
return std::strcmp(lhs.getString(),rhs.getString());
}
// Define operator!= in terms of ==
inline bool operator!=(String const& lhs, String const& rhs)
{
return !(lhs == rhs);
}
and here is string.cpp
String::String(char const* s) // C-string constructor
{
len = std::strlen(s);
str = new char[len+1];
std::strcpy(str,s);
}
char* const String::getString()
{
return str;
}
and here is main.cpp
#include <cassert>
int main()
{
String c = "c";
String d = "d";
assert(c == c);
assert(c != d);
}
I tried to include only the essential code. I left out a lot of the obvious includes. The assert(c == d) is failing and I don't understand why. The operator overload of == should have returned a true result.
std::strcmp returns 0 if the strings are equal. So your operator== will return false for equal strings and true else.
You could, for instance, switch the implementations of == and != around,
strcmp returns 0 when its arguments have equal contents.
So add a comparison with 0 to your operator==:
inline bool operator==(String const& lhs, String const& rhs)
{
return std::strcmp(lhs.getString(), rhs.getString()) == 0;
}
Also, since you probably don't want to copy the arguments each time you call operator==, I'd recommend passing them by reference.

I want to check if a class instance is already stored in a std::vector

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();
}

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

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)); });