Say I have this declaration of a priority queue:
struct orderByRewards{
bool operator() (pair<int,pair<int,int> > a, pair<int, pair<int, int> > b){
return a.first < b.first;
}
};
priority_queue<pair<int,pair<int,int> >, vector<pair<int,pair<int,int> > >, orderByRewards> Q;
I was wondering if anybody could take their time and explain me how does the compiler interpret the compare class.
It feels a little weird, especially since I am not really comfortable with templates and all OOP concepts.
Why do we need to declare the type of a single object and the container type ?
You are not required to overfload the operator(). You can declare your custom method:
typedef bool (*comp)(int,int);
bool compare(int a, int b)
{
return (a<b);
}
int main()
{
std::priority_queue<int,std::vector<int>, comp> pq(compare);
return 0;
}
Updated : As @WhozCraig pointed out: It is possible to use this object without overloading the operator() but the compiler will face an easier situation inlining operator() comparison function rather than runtime-provided dereferenced comparison function
You're essentially asking about function objects (or functors). A function object is one that overloads operator()
. You can use such an object as though it were a function. The standard provides a few comparison functors (like your orderByRewards
). For example, std::less
looks something like this:
template <class T>
struct less {
constexpr bool operator()(const T &lhs, const T &rhs) const
{
return lhs < rhs;
}
};
As we can see, the overloaded operator()
just compares the two arguments using <
and then returns the boolean result. To use this, you need to create an object of type std::less
and then use the function call syntax on it:
std::less<int> compare;
assert(compare(5, 7) == true);
Even though compare
is an object, we were able to use it like a function in compare(5, 7)
.
So now we know that your type orderByRewards
is a function object type. You are passing it as a template type argument of std::priority_queue
. The implementation of std::priority_queue
can then create objects of this comparison function object when it needs to compare elements within the queue.
Consider a simpler example:
template <typename T, typename Comp>
struct foo {
void bar(T a, T b) {
Comp compare;
if (compare(a, b)) {
std::cout << "True" << std::endl;
} else {
std::cout << "False" << std::endl;
}
}
};
It's a silly example, but it gets the point across. We can use this like so:
foo<int, std::less<int>> my_foo;
my_foo.bar(5, 7); // Will print true
We were able to configure foo
, by passing it some arbitrary comparison functor type, that its member function bar
was able to instantiate and use.
So in the same way, you are configuration std::priority_queue
by giving it a comparison functor type that it can use to order elements within the queue. This is how it determines priority between elements. In fact, the default template type argument for std::priority_queue
is std::less
.
Perhaps it would make the most sense to look at the definition of std::priority_queue
and work from there.
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> >
class priority_queue {
This says that Compare
is some type, and defaults to std::less<T>
, for T = the value_type of the underlying container. This compensates for the possibility that you might do something slightly insane like creating a priority_queue of one type, but have the underlying container hold another type (though that's not particularly likely, except by accident).
std::less
, in turn, is defined like this:
template <class T> struct less {
bool operator()(const T& x, const T& y) const;
// plus a few typedefs for the argument and return types.
};
In short, it's a type defined with only one publicly available operation: an operator()
that can be passed two items that it compares, and returns a bool
to indicate whether the first is less than the second.
Since that's what std::priority_queue
expects to use, whatever you provide must support essentially the same function call-like syntax and semantics (eg, the operator()
should take const
arguments and should itself be const-qualified).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.