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.
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.
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.
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 know I could use the following:
template <typename Pair>
struct ComparePairThroughSecond : public std::unary_function<Pair, bool>
{
bool operator ()(const Pair& p1, const Pair& p2) const
{
return p1.second < p2.second;
}
};
std::set<std::pair<int, long>, ComparePairThroughSecond> somevar;
but wondered if it could be done with boost::bind
How about the following one. I'm using boost::function to 'erase' the actual type of the comparator. The comparator is created using boost:bind itself.
typedef std::pair<int, int> IntPair;
typedef boost::function<bool (const IntPair &, const IntPair &)> Comparator;
Comparator c = boost::bind(&IntPair::second, _1) < boost::bind(&IntPair::second, _2);
std::set<IntPair, Comparator> s(c);
s.insert(IntPair(5,6));
s.insert(IntPair(3,4));
s.insert(IntPair(1,2));
BOOST_FOREACH(IntPair const & p, s)
{
std::cout << p.second;
}
The problem is that -- unless you write your code as a template or use C++0x features -- you have to name the type of the boost::bind expression. But those types usually have very complicated names.
Template argument deduction in C++98:
template<class Fun>
void main_main(Fun fun) {
set<pair<int,long>,Fun> s (fun);
…
}
int main() {
main_main(…boost::bind(…)…);
}
With auto and decltype in C++0x:
int main() {
auto fun = …boost::bind(…)…;
set<pair<int,long>,decltype(fun)> s (fun);
main_main(boost::bind(…));
}
As for the actual bind expression, I think it's something like this:
typedef std::pair<int,long> pil;
boost::bind(&pil::second,_1) < boost::bind(&pil::second,_2)
(untested)