C++ std::priority_queue uses the lambda expression - c++

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;});

Related

compile error template argument for template type parameter must be a type priority_queue? [duplicate]

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.

std::upper_bound returns const iterator in const member function

Here is a class that contains a boost::circular_buffer of some struct. I make a typedef for iterators into the contained circular_buffer.
My problem is this: when the doWork function is marked const, the returned value of std::upper_bound is not compatible with the MyIterator type due to the return value having boost::cb_details::const_traits. If I remove the const keyword from the function, all my compile errors go away.
To be clear the compiler error is this:
error: conversion from ‘boost::cb_details::iterator<boost::circular_buffer<Wrapper<int>::Sample, std::allocator<Wrapper<int>::Sample> >, boost::cb_details::const_traits<std::allocator<Wrapper<int>::Sample> > >’ to non-scalar type ‘Wrapper<int>::MyIterator {aka boost::cb_details::iterator<boost::circular_buffer<Wrapper<int>::Sample, std::allocator<Wrapper<int>::Sample> >, boost::cb_details::nonconst_traits<std::allocator<Wrapper<int>::Sample> > >}’ requested
[](const Sample& a, const Sample& b) { return a.foo < b.foo; });
Here is a self-contained example:
#include <algorithm>
#include <boost/circular_buffer.hpp>
template <typename T>
class Wrapper {
public:
struct Sample {
T foo;
};
typedef typename boost::circular_buffer<Sample>::iterator MyIterator;
Wrapper(int size) { cb.resize(size); }
void add(T val) { cb.push_back(Sample{val}); }
void doWork(T bound) const {
MyIterator iter =
std::upper_bound(cb.begin(), cb.end(), Sample{3},
[](const Sample& a, const Sample& b) { return a.foo < b.foo; });
}
boost::circular_buffer<Sample> cb;
};
int main() {
Wrapper<int> buf(100);
buf.add(1);
buf.add(5);
buf.doWork(3);
return 0;
}
So, why can't this function be const? Why does marking it const have this side-effect? I want a non-const iterator into the container, but in my real test case I don't intend to actually modify the container at all.
You're going to need a const_iterator, since you're effectively observing a const container.
Perhaps:
typedef typename boost::circular_buffer<Sample>::const_iterator MyConstIterator;
… then make iter one of these.
Someone's going to tell you that you could have avoided this with auto. That's true, but then you never would have discovered this "bug", or that const_iterators exist.
If your function is marked const then all your access to member variables will be const too.
A const container will only allow access to const_ iterators, that's just the way iterators work.

Priority Queue Comparison

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.

override map::compare with lambda function directly

Trying to override map::compare function using lambda, it seems that the following solution works.
auto cmp = [](const int&a, const int& b) { return a < b; };
std::map<int, int, decltype(cmp)> myMap(cmp);
But, I had to define cmp first and use it later.
Can I do this without defining 'cmp'?
No, you can't use lambda in unevaluated context -- i.e. template parameters as in your example.
So you must define it somewhere else (using auto) and then use decltype... the other way, as it was mentioned already is to use an "ordinal" functors
If your question is about "how to use lambda expression *once* when define a map" you can exploit implicit conversion of lambdas to std::function like this:
#include <iostream>
#include <functional>
#include <map>
int main()
{
auto m = std::map<int, int, std::function<bool(const int&, const int&)>>{
[](const int& a, const int& b)
{
return a < b;
}
};
return 0;
}
you may introduce an alias for that map type to reduce typing later...
#include <iostream>
#include <functional>
#include <map>
#include <typeinfo>
typedef std::map< int, int, std::function<bool(const int&, const int&)> > MyMap;
int main()
{
auto cmp = [](const int& a, const int& b) { return a < b; };
MyMap map(cmp);
return 0;
}
Using std::function to provide the appropriate type signature for the comparator type you can define your map type and then assign any lambda compare you wish to.
You could do something like this where the type of the map is deduced from the function you pass to a function.
#include <map>
template<class Key, class Value, class F>
std::map<Key, Value, F> make_map(const F& f) {
return std::map<Key, Value, F>{f};
}
int main() {
auto my_map = make_map<int, int>([](const int&a, const int& b) { return a < b; });
my_map[10] = 20;
}
I don't see a ton of reason for doing this but I wont say it's useless. Generally you want a known comparator so that the map can be passed around easily. With the setup above you are reduced to using template functions all the time like the following
tempalte<class F>
void do_somthing(const std::map<int, int, F>& m) {
}
This isn't necessarily bad but my instincts tell me that having a type which can ONLY be dealt with by generic functions is bad. I think it works out fine for lambda functions but that's about it. The solution here is to use std::function
#include <map>
#include <functional>
template<class Key, class Value>
using my_map_t = std::map<Key, Value, std::function<bool(const Key&, const Key&)>>;
int main() {
my_map_t<int, int> my_map{[](const int&a, const int& b) { return a < b; }};
my_map[10] = 20;
}
Now you can use any predicate you want and you have a concrete type to work with, my_map
hope this helps!
In C++20 you can do this:
std::map<int, int, decltype([](const int&a, const int& b) { return a < b; })> myMap;
int main() {
myMap.insert({7, 1});
myMap.insert({46, 2});
myMap.insert({56, 3});
for (const auto& [key,value]:myMap) {
std::cout << key << " " << value << std::endl;
}
}

How do I create a set with std::pair thats sorted based on the ::second pair member using bind

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)