populating vector into map - c++

I´m trying to populate a Point map with a vector of Points. I´m trying to make a board game where each position on the board has a point (x,y) and vector of legal moves (Point objects).
I can´t seem to be able to have a map KEY as a Point.
struct Point
{
Point() {}
Point(int ix, int iy ) :x(ix), y(iy) {}
int x;
int y;
};
Point p_source (2,2);
Point p_next1 (1,2);
Point p_next2 (1,3);
Point p_next3 (1,4);
map <Point, vector<Point> > m_point;
dict[p_source].push_back(p_next1);
dict[p_source].push_back(p_next2);
dict[p_source].push_back(p_next3);
This is the errors that I get
In member function 'bool std::less<_Tp>::operator()(const _Tp&, const
_Tp&) const [with _Tp = Point]':|
instantiated from '_Tp& std::map<_Key, _Tp, _Compare,
_Alloc>::operator[](const _Key&) [with _Key = Point, _Tp = std::vector,
std::allocator >, std::allocator, std::allocator > > >, _Compare =
std::less, _Alloc = std::allocator,
std::allocator >, std::allocator, |
instantiated from here|
c:\program files ( no match for 'operator<' in '__x < __y'| ||===
Build finished: 1 errors, 0 warnings ===|

Checking my favourite online reference it reads:
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >
> class map;
Map is an associative container that contains a sorted list of unique
key-value pairs. That list is sorted using the comparison function
Compare applied to the keys. Search, removal, and insertion operations
have logarithmic complexity. Maps are usually implemented as red-black
trees.
Since you don't provide an explicit Compare it sorts using the default std::less<Key>. Seems like we're on the right track because the errors are in that class:
In member function 'bool std::less<_Tp>::operator()(const _Tp&, const
_Tp&) const [with _Tp = Point]':|
Let's check that:
template< class T >
struct less;
Function object for performing comparisons. Uses operator< on type T.
This matches what the error messages tell us:
no match for 'operator<' in '__x < __y'
Hmm, but there's no operator< for type Point...

Your error is entirely unrelated to std::vector<> – std::map<> requires that its key either be comparable with operator<, or that you supply a custom comparitor. The easiest solution is to add the following after Point's definition:
bool operator <(Point const& lhs, Point const& rhs)
{
return lhs.y < rhs.y || lhs.y == rhs.y && lhs.x < rhs.x;
}

Related

STL Sort on nested Classes

I have a graph class that has a vector of nodes. In each node, there is a vertex and a STL list of edges. Essentially it's an adjacency list.
For my assignment, I am trying to display the vertices with the most edges. I figured I would sort the graph's vector of nodes by edge size and print the top N vertices.
So I am trying to figure out STL sort, but I'm having difficulties.
I have
std::sort(path.begin(), path.end());
Where path is the vector of nodes (node = vertex value and list of edges)
In my node class, I have
bool operator<(const Node<T>& rhs){
return size < rhs.size; //size is how many edges the vertex has
}
But it's giving me errors. How can I construct the operator< function in my node class to work with STL sort?
Here are the errors:
$ make
g++ -c -g -std=c++0x graphBuilder.cpp
In file included from /usr/lib/gcc/i486-slackware-linux/4.5.2/../../../../include/c++/4.5.2/algorithm:63:0,
from graph.h:6,
from graphBuilder.cpp:2:
/usr/lib/gcc/i486-slackware-linux/4.5.2/../../../../include/c++/4.5.2/bits/stl_algo.h: In function '_RandomAccessIterator std::__unguarded_partition(_RandomAccessIterator, _RandomAccessIterator, const _Tp&) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Node<std::basic_string<char> >*, std::vector<Node<std::basic_string<char> >, std::allocator<Node<std::basic_string<char> > > > >, _Tp = Node<std::basic_string<char> >]':
/usr/lib/gcc/i486-slackware-linux/4.5.2/../../../../include/c++/4.5.2/bits/stl_algo.h:2249:70: instantiated from '_RandomAccessIterator std::__unguarded_partition_pivot(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Node<std::basic_string<char> >*, std::vector<Node<std::basic_string<char> >, std::allocator<Node<std::basic_string<char> > > > >]'
/usr/lib/gcc/i486-slackware-linux/4.5.2/../../../../include/c++/4.5.2/bits/stl_algo.h:2280:54: instantiated from 'void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Node<std::basic_string<char> >*, std::vector<Node<std::basic_string<char> >, std::allocator<Node<std::basic_string<char> > > > >, _Size = int]'
/usr/lib/gcc/i486-slackware-linux/4.5.2/../../../../include/c++/4.5.2/bits/stl_algo.h:5212:4: instantiated from 'void std::sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<Node<std::basic_string<char> >*, std::vector<Node<std::basic_string<char> >, std::allocator<Node<std::basic_string<char> > > > >]'
graph.h:32:13: instantiated from 'void Graph<T>::topN(int) [with T = std::basic_string<char>]'
graphBuilder.cpp:10:17: instantiated from here /usr/lib/gcc/i486-slackware-linux/4.5.2/../../../../include/c++/4.5.2/bits/stl_algo.h:2211:4: error: passing 'const Node<std::basic_string<char> >' as 'this' argument of 'bool Node<T>::operator<(const Node<T>&) [with T = std::basic_string<char>]' discards qualifiers
make: *** [graphBuilder.o] Error 1
Your member function needs to be const-qualified:
bool operator<(const Node<T>& rhs) const{
EDIT
Per request, here is a bit more how I knew that you needed to make the member function const.
Divining the hidden meanings in stdlib-related compiler errors is something of an art, and something that you get better at with practice. Stdlib-related errors will often emit a whole series of compiler errors. Usually the most useful of these errors is the last one, because that one is generated from the context of the code you actually wrote, rather than coming from the bowels of the library code.
In this case, the last compiler error was:
graphBuilder.cpp:10:17: instantiated from here
/usr/lib/gcc/i486-slackware-linux/4.5.2/../../../../include/c++/4.5.2/bits/stl_algo.h:2211:4:
error: passing 'const Node >' as 'this'
argument of 'bool Node::operator<(const Node&) [with T =
std::basic_string]' discards qualifiers
I've highlighted the illuminating bits. This tells me that in OP's actual code, because of how the code is constructed (maybe the sort call is itself in a const member function? who knows...) the this pointer must be const, but as we can see from the posted declaration of operator<, the method is not const. The "qualifiers" referred to in the compiler errors are what the Standard calls "cv-qualifiers". "cv" stands for "const/volatile."
When the compiler says "Passing const X as this to Node::operator< discards qualifiers" what it's really trying to say is:
"You said X was const but then you tried to call a non-const member function through const X. In order for me to make this call, I would have to discard the const qualifier on X. I'm not allowed to do that, so you have to fix your code."
The qualifiers being "discarded" here are the qualifiers on the method itself. In other words, operator< must be a const member function, but it's not.
bool operator<(const Node<T>& rhs) const {
return size() < rhs.size();
}
Making the operator const as it should be may help with not angering the compiler.
Note: The problem arises because this is always const so the compiler expects you to promise not to change it which you specify by making the method using this to have the const qualifier.
Alternately you could make a non-member comparison for use with sort like so:
<template typename T>
struct CompareNodes {
bool operator()(const Node<T>& lhs, const Node<T>& rhs) const
{
return lhs.size() < rhs.size();
}
};
std::sort(path.cbegin(), path.cend(), CompareNodes<T>());

Why operator[] not allowed for maps but are allowed for int arrays?

I have a class with the following private members:
private:
int *vals_;
size_type *cidx_;
std::map< size_type, std::pair<size_t, unsigned int> > ridx_;
Now I am trying to access these variables in operator<< overload: (Note that m is const)
std::ostream& operator<<(std::ostream &os, const SMatrix &m)
{
os << m.cidx_[0] << endl;
os << m.ridx_[0].first << endl;
return os;
}
What I find is m.cidx_[0] will work, but m.ridx_[0].first gives an error:
error: passing 'const std::map, std::less, std::allocator > > >' as 'this' argument of '_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = unsigned int, _Tp = std::pair, _Compare = std::less, _Alloc = std::allocator > >]' discards qualifiers
Which I believe means operator[] is a modifying operator and hence contradicts the fact that m is const. But why does it work for vals_ and cidx_ which are int and size_type arrays?
std::map::operator[] inserts an element if it doesn't exist, so it cannot be used with const objects. Arrays are not class types in C++, for them a[idx] is equivalent to *(a + idx) and never mutates the array by itself.
if you look through the source code of map container, there is no map::operator [] with const cv qualifier, but your matrix object is const

How can I insert a structure as key into a map?

I'm getting a compiling error for the code below, after removing the comment characters from the first insert line. I'm unable to insert the structure into the map while inserting integers is fine.
# include <iostream>
# include <map>
using namespace std;
struct node
{int test;} temp;
int main()
{
temp.test = 24;
int test = 30;
map<node, bool> mymap1;
map<int, bool> mymap2;
//mymap1.insert(make_pair(temp, true));
mymap2.insert(make_pair(test, true));
return 0;
}
How can I fix the error?
For a type to serve as the key for a map, it has to be ordered. All that means, practically, is that operator< must be defined for the type. If you defined a global operator<(const node&, const node&), this should work fine; i.e.,
bool operator<(const node& n1, const node& n2) {
return n1.test < n2.test;
}
A std::map's keys are stored internally in a binary search tree. In order for keys to be stored and searched for in a binary search tree, they must be comparable. For example, a requirement of a binary search tree is that a left child's key is less than its parent's key and a right child's key is greater than its parent's key. However, if the keys are not comparable, how are we supposed to tell whether the children are greater or less than the parent? We cannot form a tree and therefore std::map will not work with these types.
You simply need to define the less than operator like so:
bool operator<(const node& n1, const node& n2)
{
return n1.test < n2.test;
}
This also must be a friend of your node struct if the "test" data member is private (It's public now since node is currently a struct). However, I would probably do it like this:
#include <map>
class node
{
public:
int getTest() const { return _test; }
void setTest(int test) { _test = test; }
private:
int _test;
};
bool operator<(const node& n1, const node& n2)
{
return n1.getTest() < n2.getTest();
}
int main()
{
std::map<node,bool> foo;
node n;
n.setTest(25);
foo[n] = true;
return 0;
}
Here's how to read the error messages:
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = node]’:
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_tree.h:1141: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = node, _Val = std::pair<const node, bool>, _KeyOfValue = std::_Select1st<std::pair<const node, bool> >, _Compare = std::less<node>, _Alloc = std::allocator<std::pair<const node, bool> >]’
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_map.h:469: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = node, _Tp = bool, _Compare = std::less<node>, _Alloc = std::allocator<std::pair<const node, bool> >]’
prog.cpp:15: instantiated from here
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
First, we ignore most of the 'instantiated from' lines, because they're just talking about how the templates got expanded. The important one is the last one, referring to our source code, because it tells us where the error was triggered. Of course, we knew that anyway, so we'll skip that too. We'll also ignore the path to the library header in question, because we don't really care how the compiler stores its stuff.
stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = node]’:
stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
So... our code indirectly calls ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = node]’, or if we actually do that substitution, ‘bool std::less<node>::operator()(const node&, const node&) const’. And this is a problem because there is no match for ‘operator<’ in ‘__x < __y’.
__x and __y are variables inside the std::less implementation (you should be able to guess that much). From the name, we can guess (and if we had studied the standard library, we would know) that std::less is a template function that compares two things of the same type and returns whether or not the first is less than the second.
How does it do that? By using the operator<, of course. So that's what we need to do to fix the problem: it says the operator< isn't there for what's being compared, so we have to provide it. What's being compared? nodes, of course. So we define operator< for our class.
Why does it do that? So that we can write functions that accept a comparison-operation as an argument (either a template argument or a run-time parameter - but the former is far more common), and pass std::less. That's the reason for std::less's existence: it turns the act of comparing things into a function, and actual functions are somewhat more useful.
How is that relevant? Because, like the others said, std::map actually is passing std::less as an argument. It's actually a default argument to the std::map template that's used to compare elements. After all, part of the interface of a map is that every key is unique. How are you going to check keys for uniqueness if you can't compare them? Granted, technically you would only have to compare them for equality for that to work. But it turns out that being able to order the keys makes it possible to create a much more efficient data structure. (You would know about this if you actually took courses in university about programming and CS.)
Why wasn't there a problem with int? You should be able to guess by now: operator< already naturally works for ints. But you have to tell C++ how to do it for any user types, because you might have something else in mind.
C++11
As mentioned in Andrew Rasmussen's answer, the keys of a std::map must be comparable. However, you can also provide a custom comparison object to your map instead of defining operator< for your struct. Moreover, since C++11, you can use a lambda expression instead of defining a comparison object. As a result, you can keep your code as short as follows:
auto comp = [](const node& n1, const node& n2) { return n1.test < n2.test; };
std::map<node, bool, decltype(comp)> mymap1(comp);
Code on Ideone

Problem with std::map and std::pair

I have a small program I want to execute to test something
#include <map>
#include <iostream>
using namespace std;
struct _pos{
float xi;
float xf;
bool operator<(_pos& other){
return this->xi < other.xi;
}
};
struct _val{
float f;
};
int main()
{
map<_pos,_val> m;
struct _pos k1 = {0,10};
struct _pos k2 = {10,15};
struct _val v1 = {5.5};
struct _val v2 = {12.3};
m.insert(std::pair<_pos,_val>(k1,v1));
m.insert(std::pair<_pos,_val>(k2,v2));
return 0;
}
The problem is that when I try to compile it, I get the following error
$ g++ m2.cpp -o mtest
In file included from /usr/include/c++/4.4/bits/stl_tree.h:64,
from /usr/include/c++/4.4/map:60,
from m2.cpp:1:
/usr/include/c++/4.4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = _pos]’:
/usr/include/c++/4.4/bits/stl_tree.h:1170: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = _pos, _Val = std::pair<const _pos, _val>, _KeyOfValue = std::_Select1st<std::pair<const _pos, _val> >, _Compare = std::less<_pos>, _Alloc = std::allocator<std::pair<const _pos, _val> >]’
/usr/include/c++/4.4/bits/stl_map.h:500: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = _pos, _Tp = _val, _Compare = std::less<_pos>, _Alloc = std::allocator<std::pair<const _pos, _val> >]’
m2.cpp:30: instantiated from here
/usr/include/c++/4.4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
m2.cpp:9: note: candidates are: bool _pos::operator<(_pos&)
$
I thought that declaring the operator< on the key would solve the problem, but its still there.
What could be wrong?
Thanks in advance.
The problem is this:
bool operator<(_pos& other)
Should be this:
bool operator<(const _pos& other) const {
// ^^^^ ^^^^^
Without the first const, the right-hand side of the comparison (b in a < b) cannot be const, since without const the function may modify its argument.
Without the second const, the left-hand side of the comparison (a in a < b) cannot be const, since without const the function may modify this.
Internally, the key's of a map are always const.
It should be noted that you should prefer to use nonmember functions. That is, better is a free-function:
bool operator<(const _pos& lhs, const _pos& rhs)
{
return lhs.xi < rhs.xi;
}
In the same namespace as your class. (For our example, just underneath it.)
By the way, in C++ there is no need to prefix the declaration of a struct type variable with struct. This is perfect, and preferred:
_pos k1 = {0,10};
_pos k2 = {10,15};
_val v1 = {5.5};
_val v2 = {12.3};
(Though your type names are admittedly named in an unorthodox manner. :P)
Lastly, you should prefer the make_pair utility function for making pairs:
m.insert(std::make_pair(k1,v1));
m.insert(std::make_pair(k2,v2));
It saves you from having to write out the types for the pair, and is generally easier to read. (Especially when longer type names come along.)
Signature of the less than operator needs to be bool operator<(const _pos& other) const, otherwise map can not use this operator in const functions since this member function is declared as non-const.
I think that your definition of operator< is wrong - the right hand side (argument in this case) should be marked const and it should be a const member function, e.g.
bool operator<(const _pos& other) const{
return this->xi < other.xi;
}

C++ STL:map search by iterator to another map

I'm trying to jump through some hoops to organize data in a special way. I'm including a simplified piece of code that demonstrates my pain.
I can't use boost.
I'm using the latest version of g++ in cygwin.
#include <iostream>
#include <map>
using namespace std;
int main () {
map< int,int > genmap;
map< int,int >::iterator genmapit;
map< map<int,int>::iterator,int > itermap;
// insert something into genmap
genmap.insert (make_pair(1,500) );
// find and return iterator.
genmapit=genmap.find(1);
// insert the iterator/int into itermap. Dies on each of the following 3 versions of this line.
//itermap[genmapit] = 600; // crash
//itermap.insert ( pair< map<int,int>::iterator,int >(genmapit,600) ); // crash
itermap.insert ( make_pair(genmapit,600) ); // crash
return 0;
}
So as you can see, I have 1 simple map, an iterator to that map and another map that has the first argument as an iterator to the first map.
It's clear from this:
Why can't I put an iterator in map?
That I can have an iterator as the second argument. However, the way shown above provides this:
$ make
g++ -c -o main.o main.cpp
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_function.h: In member fun
ction `bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp =
std::_Rb_tree_iterator<std::pair<const int, int> >]':
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_tree.h:871: instantiate
d from `std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _All
oc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::i
nsert_unique(const _Val&) [with _Key = std::_Rb_tree_iterator<std::pair<const in
t, int> >, _Val = std::pair<const std::_Rb_tree_iterator<std::pair<const int, in
t> >, int>, _KeyOfValue = std::_Select1st<std::pair<const std::_Rb_tree_iterator
<std::pair<const int, int> >, int> >, _Compare = std::less<std::_Rb_tree_iterato
r<std::pair<const int, int> > >, _Alloc = std::allocator<std::pair<const std::_R
b_tree_iterator<std::pair<const int, int> >, int> >]'
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_map.h:360: instantiated
from `std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_
Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator, bool> std::
map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [wit
h _Key = std::_Rb_tree_iterator<std::pair<const int, int> >, _Tp = int, _Compare
= std::less<std::_Rb_tree_iterator<std::pair<const int, int> > >, _Alloc = std:
:allocator<std::pair<const std::_Rb_tree_iterator<std::pair<const int, int> >, i
nt> >]'
main.cpp:23: instantiated from here
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_function.h:227: error: no
match for 'operator<' in '__x < __y'
make: *** [main.o] Error 1
"instantiated from here" tells me nothing and a web search gives me no info on this.
Does STL:map simply not allow for this? I can recode my app to work around this but it will be very inefficient and I would like to get this working. Is there another kind of pointer I can make for a map element I could use?
Thanks for your time.
You can't do this because std::map iterators are not random access iterators so aren't comparable with <.
Instead, you could use pointers to the value_type in the first map as a map key.
You have to learn to read the error messages. In particular look at the message that comes after the long-winded description where the error happened:
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_function.h:227: error: no
match for 'operator<' in '__x < __y'
Map iterators are not comparable with less-than operator which the map uses by default.
I suppose you can provide a comparison function that compares the pairs pointed to by the iterator, since the iterators themselves cannot be easily compared in a meaningful way.
struct CompareIterator
{
template <class FirstIter, class SecondIter>
bool operator()(FirstIter lhv, SecondIter rhv) const
{
return *lhv < *rhv;
}
};
//usage with map:
map< map<int,int>::iterator,int, CompareIterator > itermap;
std::pair defines operator<. I also used two iterator types, since it might be possible the types are different (iterator and const_iterator)
map<Key, Value>
The map iterator as key element into another map is not possible because map expects operator < to be defined by default to the key. If the Key (in this case map iterator) is not defined then you need to pass a functor as a predicate function that provides the comparison of Key (map iterator).