154

I'm trying to declare a priority_queue of nodes, using bool Compare(Node a, Node b) as the comparator function (which is outside the node class).

What I currently have is:

priority_queue<Node, vector<Node>, Compare> openSet;

For some reason, I'm getting Error: "Compare" is not a type name

Changing the declaration to priority_queue <Node, vector<Node>, bool Compare>

gives me Error: expected a '>'

I've also tried:

priority_queue<Node, vector<Node>, Compare()> openSet;
priority_queue<Node, vector<Node>, bool Compare()> openSet;
priority_queue<Node, vector<Node>, Compare<Node, Node>> openSet; 

How should I correctly declare my priority_queue?

11 Answers 11

216

Note - You may also want to check other answers, especially the one with decltype and lambda


You should declare a class Compare and overload operator() for it like this:

class Foo
{

};

class Compare
{
public:
    bool operator() (Foo, Foo)
    {
        return true;
    }
};

int main()
{
    std::priority_queue<Foo, std::vector<Foo>, Compare> pq;
    return 0;
}

Or, if you for some reasons can't make it as class, you could use std::function for it:

class Foo
{

};

bool Compare(Foo, Foo)
{
    return true;
}

int main()
{
    std::priority_queue<Foo, std::vector<Foo>, std::function<bool(Foo, Foo)>> pq(Compare);
    return 0;
}
10
  • 1
    Perfect, just what I was looking for. I never thought to make a separate class. Would the first example be considered better style? Commented Apr 19, 2013 at 18:42
  • 3
    @StevenMorad, I prefer to use class with overloaded operator(), it looks simpler.
    – awesoon
    Commented Apr 19, 2013 at 18:46
  • 6
    @soon Why do we overload the operator () ? Is this linked to how priority_queues are implemented internally? overloading > or < makes sense intuitively, but () operator not so much
    – Piyush
    Commented May 28, 2016 at 18:00
  • 2
    @Piyush, the question is about passing a custom comparator to the pritority_queue. It is possible to overload operator< and use built-in std::less comparator, however, the bool Compare(Node a, Node b) declared outside of the class Node, according to the question.
    – awesoon
    Commented May 28, 2016 at 21:05
  • 2
    @Piyush the syntax of using () is about passing a function as a parameter to another function, not about the specific operators. This is also known as a functor. See this link: en.wikipedia.org/wiki/Function_object
    – yuqli
    Commented Sep 15, 2018 at 0:31
125

The accepted answer shows how to use a class or a std::function as comparator. We can also pass a function pointer, as cute_ptr's answer already showed. However, the syntax to do so is much simpler than shown there:

class Node;
bool Compare(Node a, Node b);

std::priority_queue<Node, std::vector<Node>, decltype(&Compare)> openSet(Compare);

That is, there is no need to explicitly encode the function's type, you can let the compiler do that for you using decltype.

This is very useful if the comparator is a lambda. You cannot specify the type of a lambda in any other way than using decltype. For example:

auto compare = [](Node a, Node b) { return a.foo < b.foo; }
std::priority_queue<Node, std::vector<Node>, decltype(compare)> openSet(compare);
9
  • 3
    This is fantastic, I wonder if there are any potential traps (issues) here. Would love to see this answer get more visibility and discussion. Commented Dec 10, 2018 at 18:24
  • 1
    @Apollys: I use this method regularly (usually Compare is a lambda, which is impossible to write a declaration for), I don't know of any traps. Commented Dec 10, 2018 at 18:26
  • If you were to do this for a lambda function, where would you put the body of the lambda function? Would you store it in a variable f beforehand and then replace Compare with f?
    – Eric Auld
    Commented Mar 26, 2019 at 16:59
  • @EricAuld: Yes, Compare can be a lambda function there, as in auto Compare = [](){};. But you need to use decltype(Compare), rather than decltype(&Compare). Commented Mar 26, 2019 at 17:47
  • 1
    @BitTickler: You need to include a pointer to the comparator function when you construct the queue: Seqs pq(char_range_compare);. The template arguments specify the function type (i.e. what parameters it takes and what type it returns), it doesn't specify an actual function to call. I don't know why this doesn't give a compile-time error. GCC also happily compiles your code without a warning, and produces the same seg fault. It's because there's an attempt to call a function at address 0x0000. Commented May 4, 2021 at 21:53
31

The third template parameter must be a class who has operator()(Node,Node) overloaded. So you will have to create a class this way:

class ComparisonClass {
public:
    bool operator() (Node obj1, Node obj2) {
        //comparison code here
    }
};

And then you will use this class as the third template parameter like this:

priority_queue<Node, vector<Node>, ComparisonClass> q;
4
  • 20
    The operator method must be public.
    – knezi
    Commented Mar 6, 2017 at 8:42
  • 1
    The third template does not need to be a class. It can be the type of a function. Commented Feb 2, 2018 at 17:17
  • 1
    According to cpluplus: This may be a function pointer or function object
    – Benav
    Commented Aug 11, 2020 at 7:09
  • @Mic can we define the operator() in the Node class itself?
    – ProgramCpp
    Commented Aug 14, 2023 at 4:20
17

Answering your question directly:

I'm trying to declare a priority_queue of nodes, using bool Compare(Node a, Node b) as the comparator function

What I currently have is:

priority_queue<Node, vector<Node>, Compare> openSet;

For some reason, I'm getting Error:

"Compare" is not a type name

The compiler is telling you exactly what's wrong: Compare is not a type name, but an instance of a function that takes two Nodes and returns a bool.
What you need is to specify the function pointer type:
std::priority_queue<Node, std::vector<Node>, bool (*)(Node, Node)> openSet(Compare)

0
15

You have to define the compare first. There are 3 ways to do that:

  1. use class
  2. use struct (which is same as class)
  3. use lambda function.

It's easy to use class/struct because easy to declare just write this line of code above your executing code

struct compare{
  public:
  bool operator()(Node& a,Node& b) // overloading both operators 
  {
      return a.w < b.w: // if you want increasing order;(i.e increasing for minPQ)
      return a.w > b.w // if you want reverse of default order;(i.e decreasing for minPQ)
   }
};

Calling code:

priority_queue<Node,vector<Node>,compare> pq;
0
13

One can also use a lambda function.

auto Compare = [](Node &a, Node &b) { //compare };
std::priority_queue<Node, std::vector<Node>, decltype(Compare)> openset(Compare);
5

In case this helps anyone :

static bool myFunction(Node& p1, Node& p2) {}
priority_queue <Node, vector<Node>, function<bool(Node&, Node&)>> pq1(myFunction);
3

In the priority queue, there is a predefined boolean function "operator<()", try to overload this function as per your requirement.

bool operator<(const Node& x,const Node& y){
    return x.data>y.data;
}

priority_queue<Node> min_heap;
2
  • I watched this, but I didn't understand why he said operator< is wrong. youtube.com/…
    – Kargath
    Commented Nov 16, 2021 at 15:24
  • @Kargath The video says that for some use cases, the sorting does not relate to a “less than” comparison. Defining < to impose your custom sorting would be confusing in this case, because it wouldn’t really be a “less than” comparison. < would return true if one object comes before the other in the sorting, rather than if one is smaller than the other. Commented Aug 19, 2022 at 14:11
3

Since C++ 20, we can more concisely use a lambda for the comparator inline, without needing to assign it to a separate variable. This is because lambdas without any captures are now default constructible.

For example:

std::priority_queue<Node, std::vector<Node>, 
                       decltype([](Node& a, Node& b){return a.x < b.x;})> pq;

Note that we did not need to pass the lambda itself to the constructor, but only its type to the third template parameter. No repetition is necessary.

0

With latest c++ standard, you can actually declare a lambda function for comparator which would make the code much cleaner. Here is a sample code:

#include <queue>

class Foo
{
    public:
        int i;
};


int main()
{
    auto comparator = [](const Foo& a, const Foo& b) {
        return a.i > b.i;
    };

    std::priority_queue<Foo, std::vector<Foo>, decltype(comparator)>  pq(comparator);
    return 0;
}
1
  • 1
    This was possible since C++11, definitely not the latest standard. Also, when you wrote this, there were already two answers showing how to use a lambda function in this way. Please make sure you add value when you write an answer. Commented Sep 15, 2021 at 15:46
-1

With the help of struct also we can do this. The code will go something like below.

struct myCompare{
    bool operator()(Node &a, Node &b){
        // Your own custom logic to compare the two nodes and return a boolean value.
    }
}

priority_queue<Node, vector<Node>, myCompare> openSet;

Not the answer you're looking for? Browse other questions tagged or ask your own question.