I am trying to create a priority queue with a custom comparator but the following code gives me a compile error:
auto comparator = [](std::pair<std::vector<int>, File&> const &a, std::pair<std::vector<int>, File&> const &b) {
return a.first.front() > b.first.front();
};
std::priority_queue<std::pair<std::vector<uint64_t>, File&>,
std::vector<std::pair<std::vector<uint64_t>, File&>>,
decltype(comparator)> pq;
This is the error I am getting:
In template: no matching constructor for initialization of 'std::priority_queue<std::pair<std::vector, moderndbs::File &>, std::vector<std::pair<std::vector, moderndbs::File &>>, (lambda at
There's a mismatch in your question, between uint64_t and int. Assuming that this is squared away:
You need at least C++20 in order to compile the shown code. Prior to C++20, lambdas are not default-constructible, and you attempting to default-construct your std::priority_queue.
You need to explicitly pass the comparator to the constructor. Tested with gcc 10, with -std=c++17:
#include <queue>
#include <functional>
#include <vector>
#include <cstdint>
class File{};
void foo()
{
auto comparator = [](std::pair<std::vector<int>,
File &> const &a,
std::pair<std::vector<int>,
File &> const &b) {
return a.first.front() > b.first.front();
};
std::priority_queue<std::pair<std::vector<int>,
File &>,
std::vector<std::pair<std::vector<int>,
File &>
>,
decltype(comparator)> pq{comparator};
}
This fails with with a default-constructor pq. gcc 10 compiles the default-constructed pq with -std=c++20.
P.S.: consider replacing the File & with std::reference_wrapper, unless you really intend to do what the File & in std::pair will really do.
Related
Currently working with some ol' C++, but am having a touch of trouble with using the greater<int>() comparator for finding the top k keys with the max value in a map.
When compiling receiving the error:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:5138:17: error: no matching function for call to object of type 'std::__1::greater<int>'
if (__comp(*__first, *__result_first))
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:5160:12: note: in instantiation of function template specialization 'std::__1::__partial_sort_copy<std::__1::greater<int> &, std::__1::__hash_map_iterator<std::__1::__hash_iterator<std::__1::__hash_node<std::__1::__hash_value_type<std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, int>, void *> *> >, std::__1::__wrap_iter<std::__1::pair<std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, int> *> >' requested here
return __partial_sort_copy<_Comp_ref>(__first, __last, __result_first, __result_last, __comp);
^
Yikes that's ugly... Here's some context:
Context
I have an unordered_map<vector<string>,int>> construct which I am attempting to find the top k strings in my map which have the max int value.
#include <string>
#include <unordered_map>
#include <algorithm>
#include <functional>
#include <vector>
//...
unordered_map<vector<string>, int> database;
vector<pair <vector<string>, int> > top_k(3);
partial_sort_copy(my_map.begin(),
my_map.end(),
top_k.begin(),
top_k.end(),
greater<int>());
Not the best cpp programmer, would love to hear some suggestions you had to remedy this situation?
According to the documentation on cppreference, the comparator function requires a type signature like so:
bool cmp(const Type1 &a, const Type2 &b);
The types Type1 and Type2 must be such that an object of type RandomIt can be dereferenced and then implicitly converted to both of them.
The RandomIt iterators correspond to the top_k structure which when dereferenced has type pair <vector<string>, int>, while std::greater<int> has comparison function of bool operator()( const int& lhs, const int& rhs ). In other words, this does not work because pair <vector<string>, int> does not convert to int.
One solution is to provide your own comparator:
std::partial_sort_copy(my_map.begin(), my_map.end(), top_k.begin(), top_k.end(),
[](const pair<vector<string>, int>& lhs, const pair<vector<string>, int>& rhs) {
return lhs.second > rhs.second;
});
What do I have to do to make custom classes (that inherit from STL containers like std::vector or std::map) work with the boost::assign list_of() or map_list_of() initializer functions?
Background
I want to easily initialize a containers with a list of values. C++11 introduced initializer lists however I am stuck with C++03 so I cannot use C++11 initializer lists.
As a workaround I found the boost:assign library that provides functions like list_of() and map_list_of(). This works quite well for the STL containers like std::vector and std::map. However if I create my own containers by e.g. by extending std::vector I get compilation errors.
Example
Here is a small example
#include "boost/assign/list_of.hpp"
using namespace boost::assign;
#include <vector>
struct SpecialVector : public std::vector<int>{
foo(){/* adds functionality */}
};
int main(){
std::vector<int> v = list_of(1)(2)(3); // list_of() works well for STL containers
// The following works but requires adding items one-by-one with push_back
SpecialVector u;
u.push_back(1);
u.push_back(2);
u.push_back(3);
// The following fails when attempting to compile
SpecialVector u2 = list_of(1)(2)(3);
}
Attempting to compile the example gives me the following error:
In file included from assign_inherited.cpp:1:0:
../../../lib/boost/assign/list_of.hpp: In instantiation of 'Container boost::assign_detail::converter<DerivedTAssign, Iterator>::convert(const Container*, boost::assign_detail::default_type_tag) const [with Container = SpecialVector; DerivedTAssign = boost::assign_detail::generic_list<int>; Iterator = std::_Deque_iterator<int, int&, int*>]':
../../../lib/boost/assign/list_of.hpp:142:38: required from 'Container boost::assign_detail::converter<DerivedTAssign, Iterator>::convert_to_container() const [with Container = SpecialVector; DerivedTAssign = boost::assign_detail::generic_list<int>; Iterator = std::_Deque_iterator<int, int&, int*>]'
../../../lib/boost/assign/list_of.hpp:436:81: required from 'boost::assign_detail::generic_list<T>::operator Container() const [with Container = SpecialVector; T = int]'
assign_inherited.cpp:19:39: required from here
../../../lib/boost/assign/list_of.hpp:163:20: error: no matching function for call to 'SpecialVector::SpecialVector(boost::assign_detail::converter<boost::assign_detail::generic_list<int>, std::_Deque_iterator<int, int&, int*> >::iterator, boost::assign_detail::converter<boost::assign_detail::generic_list<int>, std::_Deque_iterator<int, int&, int*> >::iterator)'
return Container( begin(), end() );
^~~~~~~~~~~~~~~~~~~~~~~~~~~
assign_inherited.cpp:5:8: note: candidate: SpecialVector::SpecialVector()
struct SpecialVector : public std::vector<int>{
^~~~~~~~~~~~~
assign_inherited.cpp:5:8: note: candidate expects 0 arguments, 2 provided
assign_inherited.cpp:5:8: note: candidate: SpecialVector::SpecialVector(const SpecialVector&)
assign_inherited.cpp:5:8: note: candidate expects 1 argument, 2 provided
I already checked the documentation of the boost::assign library. I found the section Extending the library, however if I understand it correctly, this section deals with adding custom classes as items in the list, not with generating an initializer for a custom class. Or did I understand this wrong?
Like you said, you need to allow the construction from base types:
Live On Coliru
#include "boost/assign/list_of.hpp"
using namespace boost::assign;
#include <vector>
struct SpecialVector : std::vector<int>{
typedef std::vector<int> base;
void foo(){/* adds functionality */}
SpecialVector() : base() {}
template <typename T> explicit SpecialVector(T const& t) : base(t) {}
template <typename T, typename U> SpecialVector(T const& t, U const& u) : base(t, u) {}
template <typename T, typename U, typename V> SpecialVector(T const& t, U const& u, V const& v) : base(t, u, v) {}
};
int main(){
std::vector<int> v = list_of(1)(2)(3); // list_of() works well for STL containers
// The following works but requires adding items one-by-one with push_back
SpecialVector u;
u.push_back(1);
u.push_back(2);
u.push_back(3);
// The following fails when attempting to compile
SpecialVector u2 = list_of(1)(2)(3);
}
A comparator comp was defined as below. It works fine with std::sort, but fails to compile in the constructor of std::priority_queue. What is the problem? Thanks.
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
bool comp(int a, int b) { return a > b; }
int main()
{
vector<int> vec = {4, 2, 1, 3};
sort(vec.begin(), vec.end(), comp); // OK
priority_queue<int> q1(less<int>(), vec); // OK
priority_queue<int> q2(comp, vec); // Fail
return 0;
}
Error message:
error: no matching function for call to 'std::priority_queue<int>::priority_queue(bool (&)(int, int), std::vector<int>&)'
priority_queue<int> q2(comp, vec);
^
The type of the default comparator of std::priority_queue is std::less<T> where T is the value type. You are passing something of type bool(*)(int, int) instead. std::sort() being a function can deduce the comparator's type. Class types can't deduce their template arguments (yet - there us discussion in the C++ committee that a future version may have class templates whose template arguments can be deduced.
You can use
std::priority_queue<int, std::vector<int>, bool(*)(int, int)> q(comp);
or, avoiding a hard-to-inline function pointer:
std::priority_queue<int, std::vector<int>, std::greater<int> > q;
On OS X Mavericks, using boost 1.55.0 and clang-500.2.79 (based on LLVM 3.3svn), I'm trying to iterate over a sub-range in a std::map using boost::for_each and boost:sub_range. In my function-object, I expect to receive a std::pair &. Instead, I seem to receive a const std::pair &. Why?
#include <map>
#include <boost/range/algorithm.hpp>
#include <boost/range/sub_range.hpp>
using std::map;
using std::begin;
using std::end;
using std::pair;
using boost::for_each;
using boost::sub_range;
int main()
{
map<int, int> myMap;
sub_range<decltype(myMap)> s{
begin(myMap),
end(myMap)
};
auto f1 = [&](const pair<int, int> &) {
};
for_each(s, f1); // Compiles fine
auto f2 = [&](pair<int, int> &) {
};
for_each(s, f2); // Fails to compile
}
/Users/ambarish> clang++ main.cxx
In file included from main.cxx:1:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/map:371:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/__tree:18:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/algorithm:793:9: error: no matching function for call to object of type '<lambda at main.cxx:24:15>'
__f(*__first);
^~~
/usr/local/include/boost/range/algorithm/for_each.hpp:80:12: note: in instantiation of function template specialization
'std::__1::for_each<std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, int>, std::__1::__tree_node<std::__1::pair<int, int>, void *> *, long> >, <lambda at main.cxx:24:15> >'
requested here
return std::for_each<
^
main.cxx:26:5: note: (skipping 1 context in backtrace; use -ftemplate-backtrace-limit=0 to see all)
for_each(s, f2);
^
main.cxx:24:15: note: candidate function not viable: no known conversion from 'value_type' (aka 'pair<__key_type, __mapped_type>') to 'pair<int, int> &' for 1st argument
auto f2 = [&](pair<int, int> &) {
^
1 error generated.
It doesn't compile because the value type of std::map<int, int> is not std::pair<int,int> but std::pair<const int, int>.
The reason first one (f1) compiles is because std::pair has got this constructor:
template< class U1, class U2 >
pair( pair<U1, U2>&& p );
and because f1 takes the argument by const reference. Now there's a suitable conversion which produces a temporary that can bind to a const reference easily.
Fix:
auto f2 = [&](pair<const int, int> &) { };
// or
auto f2 = [&](pair<int, int>) { };
The code appears to be using std::for_each in the boost library implementation, and C++11 style standard lambdas are being passed to the for_each function at any rate. It really depends on how the library passes the container's iterators to the std::for_each
I'm trying to write a simple factory function for std::unordered_map. The function takes in an iterable which has a begin and end method and whose value_type is a std::pair. The following is the code that I come up with.
#include <string>
#include <unordered_map>
#include <cassert>
#include <algorithm>
template <class Iterable>
std::unordered_map<typename Iterable::value_type::first_type,
typename Iterable::value_type::second_type>
make_unordered_map(Iterable const &iter)
{
return std::unordered_map<typename Iterable::value_type::first_type,
typename Iterable::value_type::second_type>(
iter.begin(), iter.end());
}
int main()
{
std::unordered_map<std::string, int> map =
{{"a", 0}, {"b", 1}, {"c", 2}};
auto result = make_unordered_map(map);
assert(std::equal(result.begin(), result.end(), map.begin()));
return 0;
}
However, I get a long list of linker error, and it basically asks for the std::hash class specialized for std::string.
undefined reference to `std::hash<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > const>::operator()(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >) const'
I'm using GCC 4.6.1, with the -std=c++0x option. I'm pretty sure std::hash<std::string> is defined in basic_string.h, which is included in <string>.
Any idea how this happens?
You're getting your type deduction mixed up. It's important to remove qualifiers from the deduced types, so declare your template like this:
#include <functional>
template <class Iterable>
std::unordered_map<typename std::decay<typename Iterable::value_type::first_type>::type,
typename Iterable::value_type::second_type>
make_unordered_map(Iterable const &iter)
{
return std::unordered_map<
typename std::decay<typename Iterable::value_type::first_type>::type,
typename Iterable::value_type::second_type>(iter.begin(), iter.end());
}
Without this, you end up with const std::string as the key type, for which there is no specialization of std::hash.
Check out how real-world library code is written (e.g. the GCC standard library implementation) to see how to handle template types judiciously.
(By the way, std::equal is probably not the best tool for unordered maps.)