I'm trying to declare a priority queue in c++ using a custom comparison function...
So , I declare the queue as follows:
std::priority_queue<int,std::vector<int>, compare> pq;
and here's the compare function :
bool compare(int a, int b)
{
return (a<b);
}
I'm pretty sure I did this before, without a class,in a similar way, but now, this code doesn't compile and I get several errors like this :
type/value mismatch at argument 3 in template parameter list for 'template<class _Tp, class _Sequence, class _Compare> class std::priority_queue'
Is there a way to create a compare function similar to this but without using a class?
Thanks
The template parameter should be the type of the comparison function. The function is then either default-constructed or you pass a function in the constructor of priority_queue. So try either
std::priority_queue<int, std::vector<int>, decltype(&compare)> pq(&compare);
or don't use function pointers but instead a functor from the standard library which then can be default-constructed, eliminating the need of passing an instance in the constructor:
std::priority_queue<int, std::vector<int>, std::less<int> > pq;
http://ideone.com/KDOkJf
If your comparison function can't be expressed using standard library functors (in case you use custom classes in the priority queue), I recommend writing a custom functor class, or use a lambda.
You can use C++11 lambda function. You need to create lambda object, pass it to the template using decltype and also pass it to the constructor. It looks like this:
auto comp = [] (int &a, int &b) -> bool { return a < b; };
std::priority_queue<int,std::vector<int>, decltype(comp) > pq (comp);
you have to specify function type and instantiate the function in priority_queue constructor.
#include <functional>
bool compare(int a, int b)
{
return (a<b);
}
std::priority_queue<int, std::vector<int>,
std::function<bool(int, int)>> pq(compare);
This worked perfectly for me.
struct compare{
bool operator() (const int& p1,const int& p2 ){
return p1<p2;
}
};
int main(){
priority_queue<int,vector<int>, compare > qu;
return 0;
}
You can use a typedef. This compiles very well:
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;
}
std::priority_queue<int, std::vector<int>, bool (*)compare(int, int)> pq(compare);
Is another way not mentioned.
Related
I'm trying to declare a priority queue in c++ using a custom comparison function...
So , I declare the queue as follows:
std::priority_queue<int,std::vector<int>, compare> pq;
and here's the compare function :
bool compare(int a, int b)
{
return (a<b);
}
I'm pretty sure I did this before, without a class,in a similar way, but now, this code doesn't compile and I get several errors like this :
type/value mismatch at argument 3 in template parameter list for 'template<class _Tp, class _Sequence, class _Compare> class std::priority_queue'
Is there a way to create a compare function similar to this but without using a class?
Thanks
The template parameter should be the type of the comparison function. The function is then either default-constructed or you pass a function in the constructor of priority_queue. So try either
std::priority_queue<int, std::vector<int>, decltype(&compare)> pq(&compare);
or don't use function pointers but instead a functor from the standard library which then can be default-constructed, eliminating the need of passing an instance in the constructor:
std::priority_queue<int, std::vector<int>, std::less<int> > pq;
http://ideone.com/KDOkJf
If your comparison function can't be expressed using standard library functors (in case you use custom classes in the priority queue), I recommend writing a custom functor class, or use a lambda.
You can use C++11 lambda function. You need to create lambda object, pass it to the template using decltype and also pass it to the constructor. It looks like this:
auto comp = [] (int &a, int &b) -> bool { return a < b; };
std::priority_queue<int,std::vector<int>, decltype(comp) > pq (comp);
you have to specify function type and instantiate the function in priority_queue constructor.
#include <functional>
bool compare(int a, int b)
{
return (a<b);
}
std::priority_queue<int, std::vector<int>,
std::function<bool(int, int)>> pq(compare);
This worked perfectly for me.
struct compare{
bool operator() (const int& p1,const int& p2 ){
return p1<p2;
}
};
int main(){
priority_queue<int,vector<int>, compare > qu;
return 0;
}
You can use a typedef. This compiles very well:
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;
}
std::priority_queue<int, std::vector<int>, bool (*)compare(int, int)> pq(compare);
Is another way not mentioned.
I am trying to figure out the reasons why you define custom compare function differently for std::sort and std::priority_queue.
for example,
for std::sort I can do something like this:
bool compare(const vector<int>& a, const vector<int>& b)
{
return a[0] < b[0];
}
class foo
{
public:
vector<vector<int>> f(vector<vector<int>> list)
{
std::sort(list.begin(), list.end(), compare);
return list;
}
};
int main()
{
vector<vector<int>> t = { {2,1},{1,0},{3,7} };
foo n;
auto ans = n.f(t);
for (vector<int> x : ans)
{
printf("x[0]: %d , x[1]: %d \n", x[0], x[1]);
}
return 0;
}
after running the code the result is:
x[0]: 1 , x[1]: 0
x[0]: 2 , x[1]: 1
x[0]: 3 , x[1]: 7
However, if i define another function in foo like this:
vector<vector<int>> f1(vector<vector<int>> list)
{
std::priority_queue<vector<int>, vector<vector<int>>, compare> pq;
}
The compiler will not allow me to do this. The simple way for me to get around this is to make a struct inside the class like this:
struct Compare
{
bool operator()(const vector<int>& a, const vector<int>& b)
{
return a[0] < b[0];
}
};
Here is what i have so far:
From the en.cppreference.com, std::sort pass in a comparison function object, but priority_queue is passing in a Compare type. I assume this might be why I can't use the same compare function for the priority queue.
Another thought is that because std::sort is a function and priority_queue is a container, so we need to make it different?
This is all I have for now.
My most concern for this is why they are behaving so differently?
What is the major reason for this to be different? why we need it to be different?
p.s. Anyone have any good book recommendation for explaining the STL deeply and more concentrating on explaining the code of STL and why they made it like this?
You're specifying compare as the 3rd template argument for std::priority_queue, which is not the correct type name. You need to specify it as an function pointer type, (and pass the function pointer as the function argument). e.g.
std::priority_queue<vector<int>, vector<vector<int>>, decltype(compare)*> pq(compare);
or
std::priority_queue<vector<int>, vector<vector<int>>, bool (*)(const vector<int>&, const vector<int>&)> pq(compare);
std::sort is a function template, so when you can pass compare as the function argument and the template parameter could be deduced automatically (as the function pointer type); std::priority_queue is a class template, so you have to specify the template argument explicitly, you just need to specify the type correctly (as the function pointer type, just as the type of the template parameter type of std::sort which is deduced automatically).
EDIT
Since C++17 we have class template argument deduction, and then you could use it as
vector<vector<int>> f1(vector<vector<int>> list)
{
// deduced T=vector<int>, Container=vector<vector<int>>, Compare=bool (*)(const vector<int>&, const vector<int>&)
std::priority_queue pq(compare, list);
return ...
}
then we don't need to specify the template arguments.
There is statement that the compiler can't pass. I can't understand it. Can anyone tell me in detail or How to fix it ? Best wishes to you.
The statement as follow:
std::priority_queue<int,std::vector<int>,[](const int& lhs,const int& rhs)
{
return lhs<rhs;
} > pq;
The compiler given the information as follow:
type/value mismatch at argument 3 in template parameter list for
'template<class _Tp, class _Sequence, class _Compare> class std::priority_queue'
The std::priority_queue inducted in cppreference site:http://en.cppreference.com/w/cpp/container/priority_queue
mainly structure as follow:
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
The declaration you show has a value, namely a lambda, as actual template argument where the formal template argument (parameter) is a type.
Here is an example of using a type as template argument:
#include <vector>
#include <queue>
auto main()
-> int
{
struct My_less
{
auto operator()( int const a, int const b ) const
-> bool
{ return a < b; }
};
std::priority_queue< int, std::vector<int>, My_less > pq;
}
Example of using a lambda expression as comparator:
#include <vector>
#include <queue>
auto main()
-> int
{
std::priority_queue< int, std::vector<int>, auto(*)(int,int)->bool > pq{
[]( int a, int b )->bool { return a < b; }
};
}
C++11 §5.1.12/19 says “The closure type associated with a lambda-expression has a deleted (8.4.3) default constructor and a deleted
copy assignment operator.”. That means that the type of a lambda expression can not be used to instantiate the lambda from scratch. And the lambda does not convert implicitly to std::less<T> that's expected, which means you cannot use it directly as constructor argument either (and anyway std::less is stateless). But you can specify a comparator type that the lambda does convert to, and then use the lambda as constructor argument. In the above code that comparator type is a simple raw function pointer.
In practice, it is useful to define the lambda functions elsewhere and pass them to the target function as function pointers
#include <vector>
#include <functional>
#include <queue>
void foo(std::function<bool(int &a, int &b)> comparison)
{
std::priority_queue< int, std::vector<int>, decltype(comparison)> pq {
comparison
};
}
auto main()
-> int
{
auto comparison = [](int,int)->bool {
return a < b;
}
foo(Comparison);
}
As mentioned, the issue is that the third parameter of the template requires a type, not a value.
However, from C++20 non-capturing lambdas are default-constructable. Since every lambda has a unique type, this means that the following will work:
std::priority_queue<int, std::vector<int>, decltype([](int lhs, int rhs) {
return lhs < rhs;
})> pq;
// use pq like normal
If you need to use this particular comparison frequently, you can typedef it:
using my_pqueue = std::priority_queue<int, std::vector<int>, decltype([](int lhs, int rhs) {
return lhs < rhs;
})>;
// ...
my_pqueue a; // don't need to pass in the lambda to the constructor
my_pqueue b;
Live example: https://godbolt.org/z/cG3P4Y
auto comp=[](const int& lhs,const int& rhs)
{
return lhs<rhs;
};
std::priority_queue<int,std::vector<int>,decltype(comp) > pq(comp);
or
std::priority_queue<int,std::vector<int>,function<bool(const int&,const int&) > pq([](const int& lhs,const int& rhs){
return lhs<rhs;
});
For a best use, you can do that :
priority_queue<State*,vector<State*>,function<bool(const State*,const State*)>> pq([](const State* s1, const State* s2){return s1->hValue>s2->hValue;});
I've check the prototype of std::sort and std::priority_queue, the custom Compare type defined in the template looks quite the same.
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;
But actually they differ, std::sort accepts a function predicate, while std::priority_queue accepts a struct(a type). Why? Thanks in advance!.
struct cmp {
bool operator() (const int &a, const int &b) {
return a < b;
}
};
vector<int> v;
v.push_back(2);
v.push_back(3);
v.push_back(1);
// this works
sort(v.begin(), v.end(), [](const int &a, const int &b) -> bool {
return a < b;
});
// this not works
// sort(v.begin(), v.end(), cmp);
cout << v[0] << endl;
// this works
priority_queue<int, cmp> q;
// this not works
// priority_queue<int, [](const int &a, const int &b) -> bool {
// return a < b;
// }> q;
q.push(2);
q.push(3);
q.push(1);
cout << q.top() << endl;
The difference is that sort is a function template and thus the template argument for Comparator can be deduced from the type of the function argument. When you call it like this:
sort(v.begin(), v.end(), [](const int &a, const int &b) -> bool {
return a < b;
});
then the argument for Comparator is deduced to be the type of the lambda closure object.
priority_queue, on the other hand, is a class template. There's no type deduction. You specify the template argument for Compare in the type of q, and afterwards, you can only supply a function argument (to the constructor) of the appropriate type.
To use a lambda with a priority queue, you'd need to get hold of its type:
auto compare = [](const int &a, const int &b) -> bool {
return a < b;
};
std::priority_queue<int, std::vector<int>, decltype(compare)> q(compare);
You were trying to pass a lambda expression as an argument to a template type parameter. This can't work. Doing the same with sort wouldn't work either:
sort<vector<int>::iterator, [](const int &a, const int &b) -> bool {
return a < b;
}>(/*...*/);
They are actually the same, the difference is in that one is a class template and the other a function template.
Here's what you can do with the priority queue:
auto comp = [](const int& a, const int& b) { return a < b; };
priority_queue<int, std::vector<int>, decltype(comp)> q(comp);
The difference is that for function templates, the compiler will deduce template parameters from the function parameters supplied, while it won't do that for class templates. So you have to supply the type explicitly, and with a lambda (which has an anonymous type), this is annoying.
This is how I would use inbuilt function or new class as a custom comparator
priority_queue< int, vector<int>, greater<int> > third (myints,myints+4);
// using mycomparison:
priority_queue< int, vector<int>, mycomparison > q1;
class mycomparison
{
public:
bool operator() (const int& lhs, const int&rhs) const
{
return (lhs<rhs);
}
};
typedef priority_queue<int,vector<int>,mycomparison> q2;
But I wonder if I can use lambda functions there ..
First define the lambda:
auto compareFunc = [](int a, int b) { return a > b; };
Then use decltype:
typedef priority_queue<int, vector<int>, decltype(compareFunc)> q2;
Now when you use q2, pass in the function:
q2 myQueue(compareFunc);
Basically, priority_queue takes the type of a function as it's 3rd template argument, while the constructor takes a pointer to that function itself.