find struct as value in std::map - c++

I am trying to use std::map::count() to find a value, which is a custom struct, in the dictionary. The following code will not compile
typedef struct myStruct
{
int x;
int y;
}MyStruct;
MyStruct instace;
instace.x = 0;
instace.y = 1;
map<unsigned int, myStruct> myMap;
myMap[0] = instace;
if(myMap.count(instace) == 1)
{
//do something
}
and this is the error I get
no instance of overloaded function "std::map<_Kty, _Ty, _Pr, _Alloc>::count
[with _Kty=unsigned int, _Ty=myStruct, _Pr=std::less<unsigned int>,
_Alloc=std::allocator<std::pair<const unsigned int, myStruct>>]" matches the
argument list
I think the compiler does not know how to compare my struct. The third argument in the declaration of a map takes a compare function, I tried to create a compare function and pass it to the third argument in declaration like the following
struct comparer
{
bool operator()(MyStruct const& Left, MyStruct const& Right) const {
return (Left.x == Right.x && Left.y == Right.y);
}
};
map<unsigned int, myStruct, comparer> myMap;
but when I do myMap.count(), I get similar error.
I have searched google using every possible way I could describe the problem, but I did not find the answer. Can someone tell me how to solve this problem?
Thanks!

Looking at std::map::count, count takes the key and return the number of elements associated with that key. That means that your code should be:
if(myMap.count(0) == 1) // for key == 0

Related

C++ bool std::operator < error with map with key std::unordered_set<int,std::hash<int>>

when I try to insert in this map:
std::map<std::unordered_set<int >, std::pair<float, std::pair<float, float >> >
I got this error
error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const
std::_Tree<_Traits> &)' : could not deduce template argument for
'const std::_Tree<_Traits> &' from 'const
std::unordered_set,std::equal_to<_Kty>,std::allocator<_Kty>>'
My data is defined as follows:
struct Trans {
int Item;
float Prob;
float W;
};
bool operator<(const Trans &a, const Trans &b)
{
return a.Item < b.Item;
}
bool operator==( Trans c, Trans d) { return c.Item == d.Item; }
struct MyHash {
size_t operator()(const Trans& x) const { return std::hash<int>()(x.Item); }
};
std::vector<std::vector<Trans>> data;
std::map<std::unordered_set<int>, float> S1;
std::map<std::unordered_set<int >, std::pair<float, std::pair<float, float >> > S2;
std::map<std::unordered_set<int >, std::pair<float, std::pair<float, float >> > S3;
The part that has the problem:
do
{
std::unordered_set<Trans, MyHash> KS(data[i].begin(), data[i].begin() + k);
std::unordered_set<int > elem;
float esupp = 1;
float Weight = 0;
float Wesupp = 1;
for (auto const &iter : KS)
{
elem.insert(iter.Item);
esupp *= iter.Prob;
Weight += iter.W;
}
Weight = Weight / k;
/*
some code, and until here I didn't get any problem
*/
**// This the area that has the problem**
S1[elem] = std::move(S1[elem] + esupp);
Wesupp = Weight * S1[elem];
S2[elem].first = std::move(S2[elem].first + esupp);
S2[elem].second = std::make_pair(elem, Wesupp);
} while (next_combination(data[i].begin(), data[i].begin() + k, data[i].end()));
A std::map expects its key to implement the operator <, unless a comparator is supplied.
Your key type, std::unordered_set doesn't implement "less than".
As #T.C. mentions, you could use std::set instead of std::unordered_set.
Your current error, as Drew Dormann pointed out, is caused by std::unordered_set's lack of an operator <.
std::set, however, does have an overloaded operator <, so you can use that.
The problem with your code runs deeper than that, though. For instance:
S1[elem] = std::move(S1[elem] + esupp);
You are assigning a float. There's absolutely no point in using std::move, especially as S1[elem] + esupp is already an rvalue. The usual way of writing this line would be S1[elem] += esupp;
S2[elem].first = std::move(S2[elem].first + esupp);
Same problem.
S2[elem].second = std::make_pair(elem, Wesupp);
The LHS of the assignment is a std::pair<float, float>; the RHS creates a std::pair<std::unordered_set<int>, float>.
And as I mentioned in the comments, std::pair<float, std::pair<float, float>> is just bad design. It should be at least std::tuple or even better a std::array<float, 3> or even better a simple struct that makes clear what each of the three floats actually mean.
Further, using a set<int> (unordered or not) as a key in a map is a fairly weird design. Do you want to just maintain a list of set<int>-3xfloat pairings that you can iterate through, or do you actually want to be able to efficiently index with a set<int>? If you don't need the efficient indexing, just use a vector of pairs rather than a map.

Iterator over a list of pairs in C++?

I defined a list of pairs and wish to access them using an iterator, following an example.
class A{
private:
list<pair<size_type,size_type> > l_edge_;
public:
void function() const{
list<pair<size_type,size_type> >::iterator Iter_;
Iter_ = l_edge_.begin();
}
}
However, I got a compilation error. How can I fix it?
error: no match for 'operator=' (operand types are 'const iterator
{aka const std::_List_iterator<std::pair<unsigned int, unsigned int> >}' and
'std::list<std::pair<unsigned int, unsigned int> >::const_iterator
{aka std::_List_const_iterator<std::pair<unsigned int, unsigned int> >}')
My guess is that you are trying to write a const member function, and not what you copied in the question:
void function() const
{
Iter_ = l_edge_.begin();
}
Now, since the function is const, the l_edge_ member is also const, and so, begin() returns a const_iterator instead of a plain iterator. But that hardly matters because the Iter_ member is also const, so it cannot be assigned to.
Usually you do not want to declare iterators as member variables, unless very special needs. Instead, just declare a local one when you need it, and of the appropriate constness:
class A
{
private:
list<pair<size_type,size_type> > l_edge_;
public:
//const member function
void function() const
{
list< pair<size_type,size_type> >::const_iterator iter = l_edge_.begin();
}
//non-const member function
void function()
{
list< pair<size_type,size_type> >::iterator iter = l_edge_.begin();
}
};

Sorting deque of boost tuples

Not sure if I have a simple typo somewhere, but I'm running into issues in sorting a deque of tuples.
So, my deque looks like this:
std::deque<boost::tuple<unsigned int, unsigned int> > messages;
And then I have my call to sort:
sort(messages.begin(), messages.end(), msg_sort_criteria);
And my sorting function:
bool msg_sort_criteria(boost::tuple<unsigned int, unsigned int> lhs, boost::tuple<unsigned int, unsigned int> rhs)
{
return boost::get<1>(lhs) < boost::get<1>(rhs);
}
What happens is that I get errors in stl_heap.h and stl_algo.h.
For instance,
Called object type '<bound member function type>' is not a function or
function parameter.
Edit:
For clarification, this is all taking place within private members of a class.
class Messages::MessageImpl{
private:
std::deque<boost::tuple<unsigned int, unsigned int> > messages;
bool msg_sort_criteria(boost::tuple<unsigned int, unsigned int> lhs, boost::tuple<unsigned int, unsigned int> rhs)
{
return boost::get<1>(lhs) < boost::get<1>(rhs);
}
void fn()
{
sort(msg_queue_.begin(), msg_queue_.end(), msg_sort_criteria);
}
}
Mostly reposting from comment.
Change your implementation to:
class Messages::MessageImpl{
private:
std::deque<boost::tuple<unsigned int, unsigned int> > messages;
static bool msg_sort_criteria(boost::tuple<unsigned int, unsigned int> lhs,
boost::tuple<unsigned int, unsigned int> rhs)
{
return boost::get<1>(lhs) < boost::get<1>(rhs);
}
void fn()
{
sort(msg_queue_.begin(), msg_queue_.end(), &MessageImpl::msg_sort_criteria);
}
};

C++ STL wrong keys types

can't understand this: g++ compiler is angry on:
lengths.insert(pair<Deux,long>(d,one));
where
struct Deux {long big; long small};
map<Deux, long> lengths;
Deux d;
long one;
so, g++ said, that i miss operator<. after making overloaded operator< for struct Deux, i saw new interesting, but the same error:
map <long, Node*>ArrayOfNodes;
map <long, Node*>::iterator it;
for (it=ArrayOfNodes[Root]->nodes.begin();it<ArrayOfNodes[Root]->nodes.end();++it)
cout<<it->first<<endl;
also used structure Node:
struct Node {
long name;
long guest;
map <long,Node*>nodes;
/*bool operator<(const Node& node)const{
if ((*this).name<node.name) return true;
if ((*this).name>node.name) return false;
return (*this).guest<(*this).guest;
}*/
and error is:
no match for operator< in it < ((Path*)this)->Path::ArrayOfNodes.
std::map<_Key, _Tp, _Compare, _Alloc>::operator[] [with _Key = long int, _Tp = Node*,
_Compare = std::less<long int>, _Alloc = std::allocator<std::pair<const long int, Node*> >]
(((const long int&)((const long int*)(&((Path*)this)->Path::Root))))->Node::nodes.std::map<_Key, _Tp, _Compare, _Alloc>::end
[with _Key = long int, _Tp = Node*, _Compare = std::less<long int>, _Alloc = std::allocator<std::pair<const long int, Node*> >]()
The compiler complains that there is no operator < for Deux (I guess). The key must be a comparable class with operator < or you must pass a third template parameter to map - the comparator.
You see, the map keeps its keys in an ordered way. In order to order them, it needs a predicate. By default it tries to use operator <
try writing something like this:
bool operator < (Deux const & d1, Deux const & d2)
{
if(d1.big > d2.big)
return false;
if(d1.big < d2.big)
return true;
return d1.small < d2.small;
}
You did not mention the error message. Always post it!
So, I need to fork my post into two distinct sections.
Missing Declaration.
`error: 'Deux' was not declared in this scope`
That's because Deux is unknown at the point where you declare the map<>.
You need to declare Deux before map<Deux, long>, because map<Deux, long> requires the full definition of its parameters.
Missing Comparator.
`error: no match for 'operator<' in '__x < __y'`
That's because you haven't defined operator< for Deux.`
If you can define a logical operator<, i.e. one that is not arbitrarily chosen for sorting purposes, you could do it like this:
// must be in same namespace as Deux
bool operator< (Deux const &lhs, Deux const &rhs) {
return lhs.foo < rhs.foo;
}
If it needs access to non-public members, you can make it a member function:
bool operator< (Deux const &rhs) {
return this->foo < rhs.foo;
}
If such comparison would be arbitrary, do as Constantinius suggests.
Next time
You could have saved us time by posting your actual code or a minimal testcase, as well as by mentioning the error message.
My guess is that your struct is missing a compare function, to make an internal sorting of your Deux objects as keys. In a map, they have to be sorted.
This is the definition of std::map
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
So if you define a function like this:
bool compare_deux(Deux& a, Deux& b) {
return a.big < b.big;
}
and pass it as a template argument:
map <Deux, long, compare_deux> lengths;
you should be fine.
Use make_pair.
lengths.insert(make_pair<Deux,long>(d,one));
Just to add yet another reply, here's how I would implement Deux to be strictly ordered. We just use lexicographic ordering:
struct Deux
{
long big, small;
inline bool operator<(const Deux & o) const
{
return big < o.big || (!(o.big < big) && small < o.small);
}
};
std::map<Deux, T> m; // works now!
Alternatively, we could have spared ourselves the pain and said:
typedef std::pair<long, long> Deux;
std::map<Deux, T> m; // always works, lexicographic compare is provided by default
Always best not to reinvent the wheel!
Post a comment if you also want pair hashing using hash_combine to use unordered containers.
You need to declare the < operator or pass a comparison function on map creation.
struct Deux
{
long big;
long small
bool operator < (const Deux &n) const
{
if(big != n.big)
return big < n.big;
else
return small < n.small;
}
};

find() problems

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)