multiset count method not working with class comparator - c++

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

Related

Multiple Overloading of Operators

as you can see from the code I want to overload the < operator twice. 1 to sort by dist and the other by nodeID. I would like to check if there is any way to call the different overloaded methods. For example in the compLoc method, when I use the sort() method I want it to be sorted by nodeID but in other methods I want it to be sorted by dist.
struct AttSet{
int nodeID;
double dist;
bool operator < (const AttSet & str) const{
return (dist < str.dist);
}
/*
bool operator <(const AttSet & str){
return (nodeID < str.nodeID);
*/
bool operator == (const AttSet & str){
return nodeID == str.nodeID;
}};
void compLoc(Edge *edge, vector<Node*> &vertices){
int l = edge->length;
int vl = edge->head->nodeID;
int vr = edge->tail->nodeID;
/*
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end());
sort(vertices[vr]->attSet.begin(), vertices[vr]->attSet.end());
vector<AttSet> vInterSec;
set_intersection(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), vertices[vr]->attSet.begin(), vertices[vr]->attSet.end(), back_inserter(vInterSec));
*/}
You cannot have overloads that have the same signature. This holds for any function. How would you try to decide which version to use?
If you want sort the object based on different criteria you should use the sort version that takes a custom comparer function as the third argument.
Edit:
Of course you need to provide the comparer. I would suggest providing the comparers as static functions of the class if you have such power. This way you will not pollute enclosing namespace and you can access privates of the class with out exposing any getters. Since your properties are public the lambda would suffice, and probably be the best/cleanest approach.
Feeling adventurous I made a simple c++11 exercise program. For what it's worth, if you ever decided to go for proper encapsulation, I've shown both approaches:
#include <iostream>
#include <algorithm>
#include <vector>
#include <initializer_list>
#include <cassert>
using namespace std;
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v){
for(const auto& el : v){
out << el << '\n';
}
return out;
}
class A {
int a;
int b;
public:
A(std::initializer_list<int> l){
assert(l.size() == 2);
auto i = l.begin();
a = *i;
++i;
b = *i;
}
friend std::ostream& operator<<(std::ostream& stream, const A& e){
return stream << e.a << ' ' << e.b;
}
static bool compareViaA(const A& lhs, const A& rhs){
return rhs.a > lhs.a;
}
static bool compareViaB(const A& lhs, const A& rhs){
return rhs.b > lhs.b;
}
};
int main() {
std::vector<A> v {{2,3}, {3,2}, {1,4}, {4,1}};
//sort(v.begin(), v.end(), [](const A& a, const A& b){return a.a > b.a;}) // fails because of privacy violation
sort(v.begin(), v.end(), A::compareViaA);
std::cout << v << '\n';
sort(v.begin(), v.end(), A::compareViaB);
std::cout << v << '\n';
return 0;
}
Live: http://ideone.com/lDMujx.
I think you can implement this by using functor and take the comparator(operator< overload) outside the AttSet.
Here is a simple example:
struct AtrComparator {
bool distcmp;
AttrComparator(bool distcmp): distcmp(distcmp) {}
bool operator() (const AttSet &s1, const AttSet &s2) {
if(distcmp) {
return s1.dist < s2.dist;
} else {
return s1.nodeID < s2.nodeID;
}
}
}
And then you can do the sort through different feed, dist or nodeID.
.e.g:
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(true));
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(false));
You can't do that. They have the same signature exactly.
Use a functor or a lambda and pass it to whatever algorithm you want.
std::sort(std::begin(container), std::end(container),
[](const element_type& lhs, const element_type& rhs) { return ...; });
Another way to do this:
struct compare_by_node_id {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.nodeID < rhs.nodeID;
}
};
struct compare_by_dist {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.dist < rhs.dist;
}
};
And you could pass that to the algorithm like:
std::sort(std::begin(container), std::end(container), compare_by_node_id());
you cannot do that because compiler doesn't see difference between:
bool operator < (const AttSet & str) const; //this const doesn't allow to override any property of object(instance of AttSet) if I remember
and
bool operator < (const AttSet & str);
there're the same same return type, same parameter (same signature)
compiler cannot choose which one is better
There's not a great way to do this as far as I am aware, since the compiler will see these as the exact same and will throw an error. If you need to do this, use the < operator as whatever will occur the most often, and then write a method that you can call to compare two object. Something like this:
bool operator< (const Blah &blah) const {
return (most often operation)
}
bool Blah::other_operation(const Blah &blah) const {
return (other operation)
}

How to initialize priority_queue of a class in C++?

I am trying to initialize a priority_queue , Here is the code
class stdnt{
public:
int indx;
int c;
int lvl;
bool operator<(const stdnt &x)
{
return this->c > x.c;
}
};
priority_queue<stdnt> pq;
But its giving me error that passing const & discards qualifiers. How else am I supposed to do this?
You need to make the operator const so that it can be called on const instances or via const references or pointers to const:
bool operator<(const stdnt &x) const
^^^^^
Alternatively, make it a non-member:
bool operator<(const stdnt &lhs, const stdnt& rhs)
{
return lhs.c > rhs.c;
}

Overloading a bool operator with a member function

I have a class like this:
class AI
{
private:
struct Comparator
{
bool operator()(const Town* lfs, const Town* rhs)
{
return GetHeuristicCost(lfs) > GetHeuristicCost(rhs);
}
};
int GetHeuristicCost(const Town* town);
// constructor and variables
};
GetHeuristicCost returns the heuristic from the town parameter to the exit of the path.
What I am trying to do is overload the bool operator for a priority queue but it gives me the error
a nonstatic member reference must be relative to a specific object
I know why it is giving me this error but what I don't know is how to use a nonstatic function inside the Comparator struct.
GetHeuristicCost must be nonstatic
I tried moving GetHeuristicCost inside the Town class to no avail
I need to overload the operator with a struct because I need to use two different bool overloadings on the () for two different circumstances but with the same parameters (two Towns). In other words I need the struct so I can't do this:
bool operator()(const Town* lfs, const Town* rhs)
{
return GetHeuristicCost(lfs) > GetHeuristicCost(rhs);
}
Basically I plan on having two structs like this:
struct Comparator1
{
bool operator()(const Town* lfs, const Town* rhs)
{
return GetHeuristicCost(lfs) > GetHeuristicCost(rhs);
}
};
struct Comparator2
{
bool operator()(const Town* lfs, const Town* rhs)
{
return GetHeuristicCost(lfs) + GetTotalCost (lfs, rhs) > GetHeuristicCost(rhs) + GetTotalCost (lfs, rhs);
}
};
You need to construct instances of the Comparator nested class with a pointer/reference to their "outer" class instance.
class AI
{
private:
struct Comparator
{
const AI &outer;
Comparator(const AI &o):outer(o){}
bool operator()(const Town* lfs, const Town* rhs)const
{
return outer.GetHeuristicCost(lfs) > outer.GetHeuristicCost(rhs);
}
};
int GetHeuristicCost(const Town* town)const;
};
// how to use in code:
AI::Comparator comp(*this);
priority_queue<Town*, vector<Town*>, AI::Comparator> priorityQueue(comp);

The priority_queue of STL in c++

I want to construct two priority queue that has different compare method(there are two reverse priority methods named cmp1 and cmp2)
My program can't go through the compiler check.Why does such error happen and is there any better solution?
#include <iostream>
#include <queue>
#include <string>
using namespace std;
struct item
{
string name;
string sex;
string id;
double score;
friend istream& operator >> (istream &is,item& data)
{
is>>data.name>>data.sex>>data.id>>data.score;
}
/*friend bool operator < (item& a,item& b)
{
return a.score<b.score;
}*/
};
struct cmp1{
operator bool()(item& x,item& y)
{
return x.score>y.score;
}
};
struct cmp2
{
operator bool()(item& x,item& y)
{
return x.score<y.score;
}
};
int main()
{
priority_queue<item,vector<item>,cmp1> boys;
priority_queue<item,vector<item>,cmp2>girls;
item temp;
int num;
cin>>num>>temp;
for(int i=0;i<num;i++)
{
if(temp.sex=="M")
boys.push(temp);
else
girls.push(temp);
}
return 0;
}
I'm going to take a wild guess at the problem.... your comparison functors are incorrect. Instead of overloading operator bool, you need to overload the function call operator, i.e.
struct cmp1{
bool operator()(const item& x, const item& y)
{
return x.score>y.score;
}
};
struct cmp2
{
bool operator()(const item& x, const item& y)
{
return x.score<y.score;
}
};
(Perhaps this was what you intended, but just got the syntax a little wrong?)
Actually, I think the best way to do it is to use std::less and std::greater. If you have overloaded operator< and operator> for your class, you can do it like this:
std::priority_queue<item, std::vector<item>, std::greater<item>> boys;
std::priority_queue<item, std::vector<item>, std::less<item>> girls;
That way you don't have to write the functor. Don't forget to #include <functional>.
Also, don't forget that the operators have to be overloaded taking const ref arguments (you can also take them by value, but that's not usually a good idea), and as const methods, like in:
bool operator<(const item& i) const {
return value < i.value;
}
bool operator>(const item& i) const {
return value > i.value;
}
Change your operator functions to this:
struct cmp1{
bool operator()(item& x,item& y)
{
return x.score>y.score;
}
};
struct cmp2
{
bool operator()(item& x,item& y)
{
return x.score<y.score;
}
};
You have defined the methods in the comparison classes wrong.
Try the following code:
struct cmp1{
bool operator()(item& x,item& y)
{
return x.score>y.score;
}
};
You have defined the methods as operator bool() ....
Also it is nice to add const to the parameters, as const item& x for showing that you won't change their values, as well a const at the end of the function definition:
bool operator()(const item& x, const item& y) const {...}
for showing that you won't change the member fields too.
I will write the third correct version of the predcate
struct cmp1
{
bool operator()( const item &x, const item &y ) const
{
return x.score > y.score;
}
};
struct cmp2
{
bool operator()( const item &x, const item &y ) const
{
return x.score < y.score;
}
};

Ordered sort in STL containers

Sorry if the question title terminology is wrong, but here is what I want to do.I need to sort a vector of objects, but contrary to a typical comparison "less than" approach I need to re-position the objects based on some string ID property so that each same type members are positioned in consecutive order like this:
[id_town,id_country,id_planet,id_planet,id_town,id_country]
becomes this:
[id_town,id_town,id_country,id_country,id_planet,id_planet]
id_ property is string.
std::sort has a third parameter which can be used to pass a boolean predicate that acts as custom comparator. Write your own comparator acording to your specifications and use it.
For example:
struct foo
{
std::string id;
foo(const std::string& _id) : id( _id ) {}
};
//Functor to compare foo instances:
struct foo_comparator
{
operator bool(const foo& lhs , const foo& rhs) const
{
return lhs.id < rhs.id;
}
};
int main()
{
std::vector<foo> v;
std::sort( std::begin(v) , std::end(v) , foo_comparator );
}
Also, in C++11 you could use a lambda:
std::sort( std::begin(v) , std::end(v) , [](const foo& lhs , const foo& rhs) { return lhs.id < rhs.id; } );
Finally, you can also overload the comparison operators (operator> and operator<) and use comparators provided by the standard library like std::greater:
struct foo
{
std::string id;
foo(const std::string& _id) : id( _id ) {}
friend bool operator<(const foo& lhs , const foo& rhs)
{
return lhs.id < rhs.id;
}
friend bool operator>(const foo& lhs , const foo& rhs)
{
return rhs < lhs;
}
friend bool operator>=(const foo& lhs , const foo& rhs)
{
return !(lhs < rhs);
}
friend bool operator<=(const foo& lhs , const foo& rhs)
{
return !(lhs > rhs);
}
};
int main()
{
std::vector<foo> v;
std::sort( std::begin(v) , std::end(v) , std::greater );
}