I've got an error while using find() function. Here is the code:
#include <iostream>
#include <map>
#define N 100000
using namespace std;
int main (int argc, char * const argv[]) {
map<int,int> m;
for (int i=0; i<N; i++) m[i]=i;
find(m.begin(), m.end(), 5);
return 0;
}
I'm getting an compiller error:
error: no match for 'operator==' in '__first. __gnu_debug::_Safe_iterator<_Iterator, _Sequence>::operator* [with _Iterator = std::_Rb_tree_iterator<std::pair<const int, int> >, _Sequence = __gnu_debug_def::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >]() == __val'
Including 'algorithm' nothing changes. Compiling in VS2008 shows similar error.
I know about m.find(), but I realy need to use find() too.
Thanks a lot for your assistance!
P.S. Actualy, the task is to compare speed of m.find(5) and find(m.begin(), m.end(), 5), so I need to make both of them work properly.
begin() and end() on all STL containers provide access to elements of those collections. Type of those elements is known as value_type of the container. For std::map<Key, Value>, its value_type is std::pair<Key, Value>. Therefore, your find function is trying to find a pair<int, int> which is equal to 5. Since there's no operator== defined to compare pair<int, int> and int, you get the error.
The correct way to do this (so long as you want to avoid member find()) is to use std::find_if:
template <class First>
struct first_equal
{
const First value;
first_equal(const First& value)
: value(value)
{
}
template <class Second>
bool operator() (const std::pair<First, Second>& pair) const
{
return pair.first == value;
}
};
...
find_if(m.begin(), m.end(), first_equal<int>(5));
You could also overload operator== for pair and int to do what you want, but it's a very hackish way (because it will affect all your code, and because such a comparison has no meaning in general).
find() requires a parameter that can be compared to *iterator. For your map, this will be pair<int,int>. You'll need to create a dummy pair, plus a comparison functor to compare the pairs.
Just use m.find(5)
Related
I am getting below error:
:60:8: error: request for member 'push' in 'pq', which is of
non-class type 'std::priority_queue,
std::vector >, std::function, std::pair)> >(comparator)' 60 | pq.push(p1);
My code is as below:
Declared a comparator for priority_queue as below:
class comparator
{
bool operator ()(std::pair<int, int> &p, std::pair<int, int> &q)
{
return (p.second < q.second);
}
};
Declared priority queue as below:
std::priority_queue<std::pair<int, int>, vector<std::pair<int, int>>, std::function<bool(pair<int, int>, pair<int, int>)>> pq(comparator);
make pair as below:
auto p1 = make_pair(1, 3);
pushed it to priority_queue as:
pq.push(p1);
Can anyone please tell, what i am doing wrong here
The operator() must be public and should also be const qualified.
You don't need std::function here. Just supply the comparator as the third template parameter directly.
#include <queue>
#include <utility>
#include <vector>
struct comparator {
// must be public and should be const qualified:
bool operator()(std::pair<int, int> &p, std::pair<int, int> &q) const {
return p.second < q.second;
}
};
int main() {
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>,
comparator> // <- the proper comparator
pq;
auto p1 = std::make_pair(1, 3);
pq.push(p1);
}
priority_queue<pair<int, int>, vector<pair<int, int>>, comparator> pq;
static bool comparator(pair<int, int> &m, pair<int, int> &n) {
if (m.second < n.second) return true;
else return false;
}
Error:
I defined my comparator inside a class, and try to declare the priority queue inside another function in the same class, and the error happens.
The third template parameter to std::priority_queue is a type.
comparator is not a type. It is a function.
But before you can fix this, there are two more problems to fix:
types and object must be declared before they are used, and the shown code does not declare comparator before using it.
comparators must taken their parameters as const references, they are not allowed to modify them.
Therefore, your comparator should be:
static bool comparator(const pair<int, int> &m, const pair<int, int> &n)
Its type is: bool (*)(const pair<int, int> &, const pair<int, int> &)
That's what the third parameter to std::priority_queue template should be, and then the actual comparator must be passed to the object's constructor, std::priority_queue has an overloaded constructor that takes an instance of the comparator as a parameter:
static bool comparator(const pair<int, int> &m, const pair<int, int> &n) {
if (m.second < n.second) return true;
else return false;
}
priority_queue<pair<int, int>, vector<pair<int, int>>,
bool (*)(const pair<int, int> &, const pair<int, int> &)
> pq{comparator};
However, you will discover that most of this is unnecessary, and I showed it only for pedanticty's purposes. std::priority_queue's default comparator template parameter will work just fine, because std::pair implements operator<:
priority_queue<pair<int, int>, vector<pair<int, int>>> pq{comparator};
The third template argument for template type parameter must be a type, whereas comparator is a function. You may get the type of the function with decltype(&comparator).
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, decltype(&comparator)> pq(comparator);
The last cppreference example with lambda is very similar to your code https://coliru.stacked-crooked.com/view?id=86f63b09847ba22e.
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;
});
I've tried to narrow down my problem to a minimal example:
#include <algorithm>
#include <map>
#include <string>
#include <vector>
int main()
{
std::vector<int> result;
std::map<std::string, std::pair<unsigned int, std::vector<int>>> other;
if (true)
{
std::for_each(other.begin(), other.end(),
[&](std::pair<std::string, std::pair<unsigned int, std::vector<int>>> & data)
{
result.insert(result.end(), data.second.second.begin(), data.second.second.end());
});
}
return 0;
}
I get a compiler error:
error C2664: 'void main::<lambda_1b93236899a42921c1aec8d5288e5b90>::operator ()(std::pair<std::string,std::pair<unsigned int,std::vector<int,std::allocator<_Ty>>>> &) const': cannot convert argument 1 from 'std::pair<const _Kty,_Ty>' to 'std::pair<std::string,std::pair<unsigned int,std::vector<int,std::allocator<_Ty>>>> &'
As far as I can tell the lambda parameter is indeed a reference to the type that is contained by the map which we are iterating through. That is the type I am supposed to be using, right?
If I remove the amperstand before data it compiles.
Why?
I do not want to pass each element by value, as those collections will contain a lot of data in my real program.
If I replace the lambda param with auto & it compiles, which leads me to believe the type in the lambda param does not match the type contained by the map, but it sure looks like it does to me. Also, why would the original compile without & if the type is wrong?
What am I missing/not understanding?
std::map<Key, T>'s value_type is std::pair<const Key, T>, not std::pair<Key, T>. The version without an ampersand makes a copy of each pair. Since you can copy const Key to Key everything is fine. Add a const to your lambda's parameter type.
#include <algorithm>
#include <map>
#include <string>
#include <vector>
int main()
{
std::vector<int> result;
std::map<std::string, std::pair<unsigned int, std::vector<int>>> other;
if (true)
{
std::for_each(other.begin(), other.end(),
[&](std::pair<const std::string, std::pair<unsigned int, std::vector<int>>> & data)
// Add this const ^^^^^
{
result.insert(result.end(), data.second.second.begin(), data.second.second.end());
});
}
return 0;
}
I've been strugglig with the very same problem today.
I solved that making the key value type in the std::pair const:
[&](std::pair<const std::string, std::pair<unsigned int, std::vector<int>>> & data)
// ^^^^^
After thinking about that a bit, it's quite logical:
You cannot change the key_value of a std::map's entry to something different. So if it's working with an auto loop and a reference it needs to be specified as const.
The below code snippet compiles with a very important warning.
#include <map>
#include <vector>
template <typename iterator>
const std::pair<int, float> &foo(iterator it) {
return *it;
}
int main() {
std::vector<std::pair<int, float>> vector;
std::map<int, float> map;
vector.push_back(std::make_pair(0, 0.0));
map.insert(std::make_pair(0, 0.0));
const std::pair<int, float> &r1 = foo(vector.begin());
const std::pair<int, float> &r2 = foo(map.begin());
if (r1 != r2) {
return 1;
}
return 0;
}
There is an implicit conversion from std::pair<const int, float> to std::pair<int, float> during foo(map.begin()) that creates a dangling reference.
ref2.cpp: In instantiation of ‘const std::pair<int, float>& foo(iterator) [with iterator = std::_Rb_tree_iterator<std::pair<const int, float> >]’:
ref2.cpp:16:52: required from here
ref2.cpp:7:11: warning: returning reference to temporary [-Wreturn-local-addr]
return *it;
^~
We could adjust the type of r2 to std::pair<const int, float> in this case. Nevertheless, it would be useful, in the general case, to assign the results of the two calls to foo() to type-compatible references. For example, the call to foo() might be wrapped in another function that always returns std::pair<int, float>&.
Can the reference assignment be made to operatate in a way that works around the misalignment of const modifiers?
Edit
The question is really about making std::pair<K,V> work with std::pair<const K,V>; vector<> and map<> are red-herrings. (In particular, see the discussion here about why the key in std::map<> is const.)
Better sample code might be:
#include <vector>
template <typename iterator>
const std::pair<const int, float>& bar(iterator it)
{
return *it;
}
int main()
{
const std::vector<std::pair<const int, float>> v1{ std::make_pair(0, 0.0f) };
bar(v1.begin());
const std::vector<std::pair<int, float>> v2{ std::make_pair(0, 0.0f) };
bar(v2.begin());
return 0;
}
According to your comments, what you're really trying to figure out is how to make the std::map<> iterator work like std::vector<>; the result should be a std::pair<> in both cases, not std::pair<const int, ...>.
With that, I've written this hack; I'm sure it's got problems and/or could be improved:
const auto& remove_const(const std::pair<const int, float>& p) {
return reinterpret_cast<const std::pair<int, float>&>(p); // :-(
}
template <typename iterator>
const std::pair<int, float> &foo(iterator it) {
return remove_const(*it);
}
You might change:
template <typename iterator>
const std::pair<int, float> &foo(iterator it) {
return *it;
}
to:
template <typename iterator>
decltype(auto) foo(iterator it) {
return *it;
}
this requires c++14, to stay with c++11 use:
auto foo(iterator it) -> decltype(*it) {