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;
}
};
Related
I was looking at this. The author first defined operator<() in my_data and said "everything is normal". After adding a member variable, he said "operator<() does not really implement a comparison operation".
I want to know what is the difference between the two and why the former is wrong?
struct my_data
{
std::string key;
std::string value;
//first
bool operator<(const my_data data)const {
return key < data.key;
}
};
//second
struct Compare
{
bool operator()(const my_data& l, const my_data& r)
const {
return l.key < r.key;
}
};
from there
With
struct my_data
{
std::string key;
std::string value;
//first
bool operator<(const my_data data)const {
return key < data.key;
}
};
std::set<my_data> data;
You can use the class with a std::set, but your operator < isn't using all of the object, it is just comparing a single field. That is what the author of the video is complaining about. They take issue that it only compares one field of the object, and not the whole state of the object. By switching to
struct my_data
{
std::string key;
std::string value;
};
struct Compare
{
bool operator()(const my_data& l, const my_data& r)
const {
return l.key < r.key;
}
};
std::set<my_data, Compare> data;
There is no longer a "lying" operator <, but instead a custom comparator that compares just what you want.
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;
}
};
According to boost documentation - proper usage of boost::operators is to derive from it:
class A : boost::operators<A>
{
public:
bool operator < (const A&) const { return false; }
};
Now, I can use > and <= and >= because all of these operators can be implemented with <, see code snippet from boost:
template <class T, class B = operators_detail::empty_base<T> >
struct less_than_comparable1 : B
{
friend bool operator>(const T& x, const T& y) { return y < x; }
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
};
And finally less_than_comparable1 is one of boost::operators base class.
PROBLEM:
But adding such inheritance is not always convenient. E.g. this inheritance means I have to add constructor(s) to some structs, otherwise all old code, such as A{1} stops compiling:
struct A : boost::operators<A>
{
A() = default;
A(int a, int b = 0) : a(a), b(b) {}
int a;
int b;
};
bool operator < (const A&, const A&);
I tried several ways: inner class, static members of boost::operators<A> but it seems that only inheritance works.
I accept an answer that shows the way how to use boost::operators without inheritance.
I can also accept an answer, that explains why this inheritance is needed.
Ok, let's simplify a little this example, why I need inheritance in this very example below to get operator > from operator <?
template <typename A>
struct GtOperator
{
friend bool operator > (const A& l, const A& r)
{
return r < l;
}
};
struct A : private GtOperator<A>
{
bool operator < (const A&) const
{
return false;
}
};
int main() {
if (A{} > A{})
{
return -1;
}
}
Nothing else seems to work, e.g. this way does not work:
struct A
{
GtOperator<A> dummy;
bool operator < (const A&) const
{
return false;
}
};
Is it possible not to inherit from boost::operators, but still use it?
No, basically. It's intended to be inherited from. The reason it works is because argument-dependent lookup will only look for friend functions and function templates in associated classes ([basic.lookup.argdep]/4) - which are going to be A and A's base classes. If boost::operators<A> isn't a base class of A, its friend functions won't be found by name lookup.
Even with new aggregate initialization rules in C++17, A{1,2} would break because you'd have to write A{{},1,2}.
Your best bet is probably to write a macro that functions as a mixin that effectively accomplishes the same thing. So the ordering ones would be:
#define LESS_THAN_COMPARABLE(T) \
friend bool operator>(const T& x, const T& y) { return y < x; } \
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); } \
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
class A
{
public:
bool operator < (const A&) const { return false; }
LESS_THAN_COMPARABLE(A)
};
Yes, that kind of sucks. (Also these could be defined as non-member functions as well, just drop the friend and put the macro invocation outside of the class).
The other alternative, besides adding constructors and writing macros, is to hope that <=> comes to fruition and then wait a few years to be able to use it.
Is there a short-cut to using std::unordered_set with classes that implement operator== and hash? Specifically, is there a way to (1) avoid creating a stand-alone operator==(const Object& a, const Object& b) function, and (2) avoid defining an entire class just to hold size_t operator()(const Object& o) const {return o.hash();}
Of course, neither of these are problems, I'm just curious.
operator== being defined as a member function is already catered for.
If the class being used as a key has a member function hash() const then we can do something simple like this:
-
#include <unordered_map>
#include <string>
struct myclass {
std::size_t hash() const { return 0; }
bool operator==(const myclass& r) const { return true; }
};
struct self_hash
{
template<class T>
auto operator()(const T& r) const { return r.hash(); }
};
int main()
{
using mymap = std::unordered_map<myclass, std::string, self_hash>;
auto m = mymap();
}
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)
}