C++ doesnt overload operator - c++

For some reason, the custom compare seems to be skipped. Never is the debug string printed and the sorting is off.
Can anyone spot what is wrong here?
bool Communication::operator<(const Communication& second) const
{
qDebug() << "Actually sorting";
return (getName().compare(second.getName()) < 0);
}
class Communication
{
public:
bool operator<(const Communication& second) const;
QString getName() const;
void setName(QString nm);
QString commName;
}
void Communication::addComm(vector<Communication*>c)
{
// This is called for sure
lg=c;
std::sort ( lg.begin(), lg.end());
}
Edit:
Below my new approach.
bool Communication::cmp(const Communication* lhs, const Communication* rhs) const
{
return (lhs->getName().compare(rhs->getName()) < 0);
}
...error: no matching function for call to 'sort(std::vector<Communication*>::iterator, std::vector<Communication*>::iterator, <unresolved overloaded function type>)'

Your vector contains pointers:
vector<Communication*> c
but your comparison is for values. You need to implement a comparison for pointers, but this cannot be operator< because you cannot overload that operator for pointers. It should be a function or functor.
bool cmp(const Communication* lhs, const Communication* rhs)
{
return (lhs->getName().compare(rhs->getName()) < 0);
}
std::sort ( lg.begin(), lg.end(), cmp);

Operators won't be overloaded for operators. If you want to sort a sequence of pointers based on a predicate on the pointees you'll need to use a suitable predicate function, e.g.:
std::sort(lg.begin(), lg.end(),
[](Communication const* c0, Communication const* c1){
return *c0 < *c1;
});

You are sorting a vector of Communication*, but your operator< compares const Communication&.

Related

multiset count method not working with class comparator

I have this struct
struct C {
int ID;
int age;
C(int ID, int age) : ID{ID}, age{age} {}
};
I use a comparator function for a multiset
bool fncomp (const C& lhs, const C& rhs) {
return lhs.age < rhs.age;
}
multiset<C, decltype(fncomp)*> ms{fncomp};
ms.emplace(1, 15);
...
// this works fine
ms.count(C(1, 15));
However if I use a class comparator, this is no longer working.
struct classcomp {
bool operator() (const C& lhs, const C& rhs) {
return lhs.age < rhs.age;
}
};
multiset<C, classcomp> ms;
ms.emplace(1, 15);
...
// error
// ms.count(C(1, 15));
Anything makes the two different?
Elaborating on my comment above:
multiset::count is a const member function, which means that it operates on a const multiset. This includes the member variables of the multiset. The comparator is a member variable of the multiset.
Since your classcomp::operator() is not marked const, it can't be called on a const object, and so it fails to compile.
This works for the function pointer example, because it's the pointer that is const in that case.
bool operator() (const C& lhs, const C& rhs) const {
return lhs.age < rhs.age;
}
This would fix things to compile in this link you provided, courtesy of #Marshall -> https://stackoverflow.com/a/71384594/10630957

How to compare and assign between std::vector<T> and std::vector<std::reference_wrapper<T>>?

Here are two different type of std::vector, as an example:
std::vector<std::reference_wrapper<MyClass>> rv;
std::vector<MyClass> v;
A possible way to assign between them is:
for (const auto& mc : rv) {
v.push_back(mc.get());
}
It works. But ugly and maybe slow. The same as comparison:
bool is_same(std::vector<MyClass>& v, std::vector<std::reference_wrapper<MyClass>>& rv) {
if (v.size()!=rv.size()) {
return false;
}
for (size_t i = 0; i < v.size(); v++) {
if (v[i]!=rv[i].get()) {
return false;
}
}
return true;
}
Is there any better way to do this work? Smart and quick.
Since std::reference_wrapper is implicitly convertible to a reference to the type it holds, you can assign one to MyClass.
So a better way to initialize one with the other is the appropriate vector constructor:
std::vector<MyClass> v(begin(rv), end(rv));
Or, if you really need to assign:
v.assign(begin(rv), end(rv));
You can do the comparison by applying the std::mismatch algorithm, again thanks to the implicit conversion provided by std::reference_wrapper:
bool is_same(std::vector<MyClass> const& v, std::vector<std::reference_wrapper<MyClass>> const& rv) {
return v.size() == rv.size() &&
end(v) == std::mismatch(begin(v), end(v), begin(rv), end(rv)).first;
}
As a general rule of thumb, it's always good to consult the standard algorithm library before writing loops yourself. It makes your own code more readable by giving verbs and nouns to computation steps. And has the benefit of allowing for any optimizations the standard library can offer.
As cppleaner pointed out, I should have consulted the library more closely myself. is_same can be implemented even more easily by a simple call to std::equal
return std::equal(begin(v), end(v), begin(rv), end(rv));
Idiomatic is_same implementation:
bool is_same(std::vector<MyClass>& v, std::vector<std::reference_wrapper<MyClass>>& rv) {
return std::equal(begin(v), end(v), begin(rv), end(rv),
[](const MyClass& c, const std::reference_wrapper<MyClass>& rc) {
return c == rc.get();
});
}
Alternately, you can write custom:
class MyClass {
bool operator ==(const MyClass&);
};
bool operator != (const MyClass&, const MyClass&);
bool operator == (const MyClass&, const std::reference_wrapper<MyClass>&);
bool operator == (const std::reference_wrapper<MyClass>&, const MyClass&);
bool operator != (const MyClass&, const std::reference_wrapper<MyClass>&);
bool operator != (const std::reference_wrapper<MyClass>&, const MyClass&);
and client code (this is redundant: you could just use the implementation as an operation):
bool is_same(const std::vector<MyClass>& v,
const std::vector<std::reference_wrapper<MyClass>>& rv) {
return v == rv;
}
Note: Consider using const on your arguments, where possible.

Two overloading functions for the same operator and class

I want to use a sorting algorithm to sort my vector of clients, but the problem is I have two different criteria to sort them.
To display them to the screen and to save them into a file I need to sort them by ID, but to use it for some other stuff (like knowing the top ten worst clients) I need to sort them by the sum of money they've spent.
These are the overloading functions of the operator== for the client class, but obviously they can't co-exist. Can someone give me a solution for this?
class Client
{
public:
//...
unsigned int getID() const;
double getSum() const;
//...
private:
unsigned int ID;
//...
double sum;
};
bool operator==(const Client &LHS, const Client &RHS)
{
return (LHS.getID() == RHS.getID());
}
bool operator==(const Client &LHS, const Client &RHS)
{
return (LHS.getSum() == RHS.getSum());
}
One of the std::sort function overloads takes a comparator, use that form and provide it with two independent functions or functors (or lambdas) for each instantiation.
class Client
{
public:
//...
unsigned int getID() const;
double getSum() const;
//...
private:
unsigned int ID;
//...
double sum;
};
bool CompareByID(const Client &LHS, const Client &RHS)
{
return (LHS.getID() < RHS.getID());
}
bool CompareBySum(const Client &LHS, const Client &RHS)
{
return (LHS.getSum() < RHS.getSum());
}
// ...
std::sort(container.begin(), container.end(), CompareByID);
Note the sort requires a comparison that obeys its ordering requirements, usually it uses a less than comparison to order the elements. The exact comparison can be different, but needs to obey the same ordering requirements (for further reading, see the information for the std::sort algorithm, and this on strict weak ordering).
As suggested you could use std:sort algorithm.
You need to create 2 function each for sum and Id comparison and pass them as function pointer for comparison.
bool compare_by_ID(const Client &LHS, const Client &RHS)
{
return (LHS.getID() < RHS.getID());
}
bool compare_by_sum(const Client &LHS, const Client &RHS)
{
return (LHS.getSum() < RHS.getSum());
}
and to use them you need to invoke sort in this way
vector<Client> v;
// assume v contains list of clients.
// for comparison by sum
std:sort(v.begin(),v.end(),compare_by_sum);
// for comparison by Id
std:sort(v.begin(),v.end(),compare_by_ID);
Apart from comparison function you could use more sophisticated approach by using functors or function objects.
Instead of relying on operator< to do your sorting, you can explicitly pass a comparator to std::sort:
std::vector<Client> vec;
...
auto sortByID = [](auto lhs, auto rhs){ return lhs.getID() < rhs.getID(); };
std::sort(vec.begin(), vec.end(), sortByID);
//vec is now sorted by ID
auto sortBySum = [](auto lhs, auto rhs){ return lhs.getSum() < rhs.getSum(); }
std::sort(vec.begin(), vec.end(), sortBySum);
//vec is now sorted by Sum

C++ overloading operator< error

Why am I receiving an error when I do not put const in the function bool operator<(const Node& otherNode) //const?
stl_algo.h:91: error: passing 'const Node' as 'this' argument of 'bool Node::operator<(const Node&)' discards qualifiers
Should all the overloaded operators be constant?
class Node {
public:
double coordinate;
bool operator==(const Node& other) const{
return coordinate == other.coordinate;
}
bool operator<(const Node& other) const{
return coordinate < other.coordinate;
}
};
Not all operators, but == and < should definitely be made const, yes. They logically don't modify either of the objects being compared.
The error likely comes from calling a non-const method from a const one, e.g.:
bool isSmaller(const Node& other) const
{
return *this < other;
}
In this case, since the method isSmaller is const, this is implicitly a const object, therefore operator < also has to be const in order for the call within that context to be valid.
From the error message, it appears that Node::operator < is being called on a const object, from a function in stl_algo.h - sorting/ordering functions, hashing functions, etc.
Comparison operators, such as <, >, <=, >=, ==, != should operate on const objects in general, because it makes no sense if any objects being compared can be changed by the comparison. But you could declare the comparisons as non-member functions in order to ensure symmetry between both operands.
class Node {
public:
double coordinate;
};
inline operator<(const Node& lhs, const Node& rhs)
{
return lhs.coordinate < rhs.coordinate;
}
Have you try to delete the const modifier of the method? Also, as #LuchianGrigore sugest, you can use the this keyword:
bool operator< (const Node& other) {
return this.coordinate < other.coordinate;
}

Error using std::find with operator==

I am getting an error using std::find on the following structure ...
struct ComplianceOrderRecord {
explicit ComplianceOrderRecord(IOrder& order);
bool operator ==(const ComplianceOrderRecord& other) const;
double price;
};
inline bool ComplianceOrderRecord::operator ==(const ComplianceOrderRecord& other) const {
return price == other.price;
}
I use it as follows...
inline void Compliance::RemoveComplianceOrderRecord(const ComplianceOrderRecord& order) {
auto it = std::find(m_compliantOrderList.begin(),
m_compliantOrderList.end(), order);
if(it == m_compliantOrderList.end()) {
return;
}
m_compliantOrderList.erase(it);
}
The error is...
error C2679: binary '==' : no operator found which takes a right-hand operand of type 'const ComplianceOrderRecord' (or there is no acceptable conversion)
Any help in understanding this error would be very appreciated.
Your operator== should be a const member, or even better, a freestanding function.
This error can be reproduced if m_compliantOrderList is not a container<ComplianceOrderRecord >. (Perhaps it is a container of pointers, or some other completely unrelated class.
Edit:
Your equality operator can compare two instances of ComplianceOrderRecord, but find needs to compare a pointer against an object. Overloading an operator to perform this kind of comparison would be bizarre, so you could use find_if with a custom predicate, such as:
struct RecordIsEqualTo
{
const ComplianceOrderRecord* record;
RecordIsEqualTo(const ComplianceOrderRecord& r): record(&r) {}
bool operator() (const ComplianceOrderRecord* r) const { return *record == *r; }
};
std::find_if(m_compliantOrderList.begin(), m_compliantOrderList.end(),
RecordIsEqualTo(order) );
or a lambda version thereof.
Your operator== function should be const. As it is, you can't call it on a const object (or a reference to const.
Try a const method:
inline bool ComplianceOrderRecord::operator ==(const ComplianceOrderRecord& other) const {
return price == other.price;
}