Reputation: 646
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.
Upvotes: 1
Views: 954
Reputation: 7212
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.
Upvotes: 2