Errors when using map() in C++ - c++

I wrote a piece of code and used map and vector but it shows me something I can't get. I'll be thankful if someone help me in this way and correct my code or give me some hints.
The code is:
// For each node in N, calculate the reachability, i.e., the
// number of nodes in N2 which are not yet covered by at
// least one node in the MPR set, and which are reachable
// through this 1-hop neighbor
std::map<int, std::vector<const NeighborTuple *> > reachability;
std::set<int> rs;
for (NeighborSet::iterator it = N.begin(); it != N.end(); it++)
{
NeighborTuple const &nb_tuple = *it;
int r = 0;
for (TwoHopNeighborSet::iterator it2 = N2.begin (); it2 != N2.end (); it2++)
{
TwoHopNeighborTuple const &nb2hop_tuple = *it2;
if (nb_tuple.neighborMainAddr == nb2hop_tuple.neighborMainAddr)
r++;
}
rs.insert (r);
reachability[r].push_back (&nb_tuple);
}
/*******************************************************************************/
//for keepping exposition of a node
std::map<Vector, std::vector<const NeighborTuple *> > position;
std::set<Vector> pos;
for (NeighborSet::iterator it = N.begin(); it != N.end(); it++)
{
NeighborTuple nb_tuple = *it;
Vector exposition;
pos.insert (exposition);
position[exposition].push_back (&nb_tuple);
}
and the errors are for this line: position[exposition].push_back (&nb_tuple);
and the errors are:
/usr/include/c++/4.1.2/bits/stl_function.h: In member function ‘bool std::less<_
Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = ns3::Vector3D]’:
/usr/include/c++/4.1.2/bits/stl_map.h:347: instantiated from ‘_Tp& std::map<_K
ey, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = ns3::Vector3D, _Tp = std::vector<const ns3::olsr::NeighborTuple*, std::allocator<const ns3::olsr::NeighborTuple*> >, _Compare = std::less<ns3::Vector3D>, _Alloc = std::allocator<std::pair<const ns3::Vector3D, std::vector<const ns3::olsr::NeighborTuple*, std::allocator<const ns3::olsr::NeighborTuple*> > > >]’
../src/routing/olsr/olsr-routing-protocol.cc:853: instantiated from here
/usr/include/c++/4.1.2/bits/stl_function.h:227: error: no match for ‘operator<’ in ‘__x < __y’
debug/ns3/ipv6-address.h:432: note: candidates are: bool ns3::operator<(const ns3::Ipv6Address&, const ns3::Ipv6Address&)
debug/ns3/nstime.h:475: note: bool ns3::operator<(const ns3::Time&, const ns3::Time&)
debug/ns3/ipv4-address.h:305: note: bool ns3::operator<(const ns3::Ipv4Address&, const ns3::Ipv4Address&)
debug/ns3/address.h:231: note: bool ns3::operator<(const ns3::Address&, const ns3::Address&)
debug/ns3/type-id.h:376: note: bool ns3::operator<(ns3::TypeId, ns3::TypeId)
Thanks in advance.
Bahar

std::map is a sorted container of pairs. As such, keys in the map must have operator <() defined. Make sure Vector has the less-than operator defined.
For example:
class Vector {
int len, ang;
friend bool operator<(const Vector&, const Vector&);
};
bool operator<(const Vector& v1, const Vector& v2)
{
return true_if_v1_is_less_than_v2(); // you define what "less than" means
}
Of course, there other ways to do this. You may make operator< a member function. Or you may have the two member data public and the operator a non-member, non-friend function. Or you may define operator< in an anonymous namespace, to enhance information hiding. Or you may use a comparator other than operator<.

You declared the position object as followed : std::map<Vector, std::vector<const NeighborTuple *> > position;
And you are trying to push NeighborTuple * inside...
Try using const NeighborTuple *

I notice that you seem to have a pushback line that compiles and a line that does not.
The difference might be that you have a const in the first case
NeighborTuple const &nb_tuple = *it;

Related

const arguments in std::remove_if

I'm going to remove elements from a list of pairs. When I'm using a pair like
std::pair<const int, bool>
I get the following compilation error:
In file included from /usr/local/include/c++/6.1.0/utility:70:0,
from /usr/local/include/c++/6.1.0/algorithm:60,
from main.cpp:1:
/usr/local/include/c++/6.1.0/bits/stl_pair.h: In instantiation of
'std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1,
_T2>&&) [with _T1 = const int; _T2 = bool]':
/usr/local/include/c++/6.1.0/bits/stl_algo.h:868:16: required from
'_ForwardIterator std::__remove_if(_ForwardIterator, _ForwardIterator,
_Predicate) [with _ForwardIterator = std::_List_iterator > _Predicate =
__gnu_cxx::__ops::_Iter_pred&)> >]'
/usr/local/include/c++/6.1.0/bits/stl_algo.h:936:30: required from
'_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter =
std::_List_iterator > _Predicate =
main()::&)>]'
main.cpp:17:32: required from here
/usr/local/include/c++/6.1.0/bits/stl_pair.h:319:8: error: assignment
of read-only member 'std::pair::first'
first = std::forward(__p.first);
This is the sample code:
int main()
{
int id = 2;
std::list< std::pair <const int, bool> > l;
l.push_back(std::make_pair(3,true));
l.push_back(std::make_pair(2,false));
l.push_back(std::make_pair(1,true));
l.erase(std::remove_if(l.begin(), l.end(),
[id](std::pair<const int, bool>& e) -> bool {
return e.first == id; }));
for (auto i: l) {
std::cout << i.first << " " << i.second << std::endl;
}
}
I know that (please correct me If I am wrong):
I will have exactly the same problem as long as there is constness in any element of the list, for example, a list <const int> will also return a compilation error.
If I remove the const in the first element of the pair the code will work.
The more elegant and efficient way to do it is by using the remove_if list method, like this:
l.remove_if([id](std::pair<const int, bool>& e) -> bool {
return e.first == id; });
but my question is, what are exactly the inner workings of std::remove_if that impose the elements of the container not being const?
The general std::remove_if shuffles item values around to put the logically erased values at the end of the sequence (it's typically used in combination with member function erase to actually remove the logically erased values). It can't do that shuffling when an item isn't copyable or movable. Instead use std::list::remove_if.
If you look at the type and iterator requirements of std::remove_if, you can see that the implementation must be similar to the following (from the link above):
template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
first = std::find_if(first, last, p);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!p(*i))
*first++ = std::move(*i);
return first;
}
I.e., the algorithm assumes only that the iterators have forward capabilities, and elements are moveable, and it moves elements around. Of course, moves can't be done on const objects.

error in type conversion in operator overloading

I have a template class and I need to overload operator ==. I do this in the following way
template <typename T>
class Polynomial {
vector<T> coefficients;
public:
Polynomial(vector<T> c);
bool operator ==(const Polynomial& second) const {
const typename vector<T>::iterator thisBegin = this->coefficients.begin();
const typename vector<T>::iterator secondBegin = second.coefficients.begin();
for ( ; ((thisBegin != this->coefficients.end()) &&
(secondBegin != second.coefficients.end()));
++thisBegin, ++secondBegin) {
if (*thisBegin != *secondBegin)
return false;
}
while (thisBegin != this->coefficients.end()) {
if (*thisBegin != 0)
return false;
++thisBegin;
}
while (secondBegin != second.coefficients.end()) {
if (*secondBegin != 0)
return false;
++secondBegin;
}
return true;
}
};
However, when I create two objects of this class with T=int and try to apply this operator
Polynomial<int> first(firstVector);
Polynomial<int> second(secondVector);
std::cout << (first == second) << std::endl;
I got the error
problem2.cpp: In instantiation of ‘bool Polynomial<T>::operator==(const Polynomial<T>&) const [with T = int; Polynomial<T> = Polynomial<int>]’:
problem2.cpp:63:32: required from here
problem2.cpp:23:83: error: conversion from ‘std::vector<int, std::allocator<int> >::const_iterator {aka __gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >}’ to non-scalar type ‘std::vector<int, std::allocator<int> >::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >}’ requested
Can someone point out what's wrong with this conversion? Thanks!
You are trying to convert a const_iterator to an iterator:
const typename vector<T>::iterator thisBegin = this->coefficients.begin();
this is const in this context, so this->coefficients.begin(); returns a const_iterator. Try this:
typename vector<T>::const_iterator thisBegin = this->coefficients.begin();
Note also that thisBegin is not const, as in your example. This is because you then do this kind of thing:
++secondBegin;
which requires the const_iterator to be non-const (meaning you can modify the iterator, but not the thing it points to).
your method is const that mean that you can only call const functions on this and
you passing const reference to method, so you can only call const functions on it
So, both
this->coefficients.begin();
second.coefficients.begin()
returns const iterators.
You cannot assign them to non-const ones.
There is a solution:
vector<T>::const_iterator& thisBegin = this->coefficients.begin();
vector<T>::const_iterator& secondBegin = second.coefficients.begin();
(use references to const_iterator)
Even better:
auto& thisBegin = this->coefficients.begin();
auto& secondBegin = second.coefficients.begin();
(use references to auto, C++11 feature)
BTW, you can simply compare two vectors using std::mismatch

map, lambda, remove_if

So, i've problem with std::map, lambda and stl algorithm(remove_if). Actually, same code with std::list or std::vector works well.
My test example :
#include <map>
#include <iostream>
#include <algorithm>
struct Foo
{
Foo() : _id(0) {}
Foo(int id) : _id(id)
{
}
int _id;
};
typedef std::map<int, Foo> FooMap;
int main()
{
FooMap m;
for (int i = 0; i < 10; ++i)
m[i + 100] = Foo(i);
int removeId = 6;
// <<< Error here >>>
std::remove_if(m.begin(), m.end(), [=](const FooMap::value_type & item) { return item.second._id == removeId ;} );
for (auto & item : m )
std::cout << item.first << " = " << item.second._id << "\n";
return 0;
}
Error message :
In file included from /usr/include/c++/4.6/utility:71:0,
from /usr/include/c++/4.6/algorithm:61,
from main.cxx:1:
/usr/include/c++/4.6/bits/stl_pair.h: In member function ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = const int, _T2 = Foo, std::pair<_T1, _T2> = std::pair<const int, Foo>]’:
/usr/include/c++/4.6/bits/stl_algo.h:1149:13: instantiated from ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::_Rb_tree_iterator<std::pair<const int, Foo> >, _Predicate = main()::<lambda(const value_type&)>]’
main.cxx:33:114: instantiated from here
/usr/include/c++/4.6/bits/stl_pair.h:156:2: error: assignment of read-only member ‘std::pair<const int, Foo>::first’
I don't understand what's wrong here. So, i gladly to read some advices/directions about it. My goal - use new lambda-style with std::map and algorithms, such as remove_if.
g++ 4.6, -std=c++0x.
The problem is that std::map<K,V>::value_type is std::pair<const K, V>, aka .first is const and not assignable. Lambdas have nothing to do with the problem here.
std::remove_if "removes" items by moving the elements of the container around, so that everything that does not fit the predicate is at the front, before the returned iterator. Everything after that iterator is unspecified. It does that with simple assignment, and since you can't assign to a const variable, you get that error.†
The name remove can be a bit misleading and in this case, you really want erase_if, but alas, that doesn't exist. You'll have to make do with iterating over all items and erasing them by hand with map.erase(iterator):
for(auto it = map.begin(), ite = map.end(); it != ite;)
{
if(it->second._id == remove_id)
it = map.erase(it);
else
++it;
}
This is safe because you can erase individual nodes in the tree without the other iterators getting invalidated. Note that I did not increment the iterator in the for loop header itself, since that would skip an element in the case where you erase a node.
† By now, you should have noticed that this would wreak havoc in the std::map's ordering, which is the reason why the key is const - so you can't influence the ordering in any way after an item has been inserted.
You could use find and erase for the map. It's not as convenient as remove_if, but it might be the best you've got.
int removeId = 6;
auto foundIter = m.find(removeId);
// if removeId is not found you will get an error when you try to erase m.end()
if(foundIter != m.end())
{
m.erase(foundIter);
}

object in a set iterator

I can get a method of a class in a set iterator ?
#include <iostream>
#include <string>
#include <set>
class student{
public:
student(std::string n){
name=n;
}
void print(){
std::cout << name << std::endl;
}
bool operator < (const student & s1){ return true;}
bool operator = (const student & s1){ return true;}
private:
std::string name;
};
int main(){
std::set<student> studs;
studs.insert(student("name01"));
studs.insert(student("name02"));
std::set<student>::iterator it;
for(it = studs.begin(); it != studs.end(); it++)
(*it).print() ;
}
I get this error
students.cpp: In function ‘int main()’:
students.cpp:22: error: passing ‘const student’ as ‘this’ argument of ‘void student::print()’ discards qualifiers
/usr/include/c++/4.2.1/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = student]’:
/usr/include/c++/4.2.1/bits/stl_tree.h:982: 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 = student, _Val = student, _KeyOfValue = std::_Identity<student>, _Compare = std::less<student>, _Alloc = std::allocator<student>]’
/usr/include/c++/4.2.1/bits/stl_set.h:307: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = student, _Compare = std::less<student>, _Alloc = std::allocator<student>]’
students.cpp:18: instantiated from here
/usr/include/c++/4.2.1/bits/stl_function.h:227: error: passing ‘const student’ as ‘this’ argument of ‘bool student::operator<(const student&)’ discards qualifiers
with
bool operator<(const student & s1) const { return true;}
bool operator==(const student & s1) const { return true;}
now work!! O_o',
#include <iostream>
#include <string>
#include <set>
class student{
public:
student(std::string n){
name=n;
}
void print() const {
std::cout << name << std::endl;
}
bool operator<(const student & s1) const { return true;}
bool operator==(const student & s1) const { return true;}
private:
std::string name;
};
int main(){
std::set<student> studs;
studs.insert(student("name01"));
studs.insert(student("name02"));
std::set<student>::iterator it;
for(it = studs.begin(); it != studs.end(); it++)
it->print() ;
}
You need to add a const qualifer to your print member function:
void print() const
{
std::cout << name << std::endl;
}
Objects in an std::set are necessarily const, since they are used as keys. When an object (or reference) is constant, you can only call member functions of that object which are declared with the const qualifier.
You also want const qualifiers on both the == and < operator overload functions. (And don't forget to change = to == as pointed out in the comments.)
Yes, though it->print() is more intuitive.
A naive world-view is that iterators are a bit like pointers. There is more to it than that, as explained here.
The most obvious form of iterator is a
pointer: A pointer can point to
elements in an array, and can iterate
through them using the increment
operator (++). But other forms of
iterators exist. For example, each
container type (such as a vector) has
a specific iterator type designed to
iterate through its elements in an
efficient way.
You want operator==, not operator=.
Your operator< definition violates the requirements of std::set, and is inconsistent with your operator<. That is, according to your operator<, nothing is equivalent, but according to your operator==, everything is equal. Operator< should define a irreflexive, transitive, and asymmetric (for non-equivalent values) relation.
Objects in a set are necessarily const, and so to call a function on such an object that function must be declared with the const qualifier. Specifically, print() should be declared void print() const.
Similarly, operator< should be declared with the const qualifier. std::set requires that operator< can be called with const objects. Another valid option would be to make operator< a non-member function and to take both objects by value (bad) or const reference (good).
While not required in your example, operator== should also be declared with the const qualifier.
Write your print() function like this:
void print() const //<---- note this 'const'
{
std::cout << name << std::endl;
}
Now your code should work now. :-)
By the way, such functions with const keyword appearing on the right side, are called const member function, as they cannot change any member-data of the class.
See this FAQ: [18.10] What is a "const member function"?
#include <iostream>
#include <set>
using namespace std;
class Boxer{
public:
string name;
int strength;
};
struct Comp{
bool operator()(const Boxer& a, const Boxer& b){
return a.strength > b.strength;
}
};
int main(){
Boxer boxer[3];
boxer[0].name="uday", boxer[0].strength=23;
boxer[1].name="manoj", boxer[1].strength=33;
boxer[2].name="rajiv", boxer[2].strength=13;
set< Boxer, Comp> s;
s.insert(boxer[0]);
s.insert(boxer[1]);
s.insert(boxer[2]);
set< Boxer, Comp>::iterator it = s.begin();
Boxer b = *it;
cout<<b.name;
//result is Manoj
return 0;
}

C++ - Using std::count() with abstract data types?

My code is using std::count() on a list of an abstract data type that i have defined. (Sommet or Edge in english). But it doesn't work, although i've overloaded the < and == operators like this :
bool operator< (const Sommet &left, const Sommet &right)
{
if(left.m_id_sommet < right.m_id_sommet)
return true;
return false;
}
bool operator== (const Sommet &left, const Sommet &right)
{
if(left.m_id_sommet == right.m_id_sommet)
return true;
return false;
}
Just notice that this worked using std::sort() and std::unique().
The errors are:
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h: In function 'typename std::iterator_traits<_Iterator>::difference_type std::count(_InputIterator, _InputIterator, const _Tp&) [with _InputIterator = __gnu_cxx::__normal_iterator<Sommet*, std::vector<Sommet, std::allocator<Sommet> > >, _Tp = __gnu_cxx::__normal_iterator<Sommet*, std::vector<Sommet, std::allocator<Sommet> > >]':
Graphe.cpp:43: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:422: error: no match for 'operator==' in '__first.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = Sommet*, _Container = std::vector<Sommet, std::allocator<Sommet> >]() == __value'
Sommet.h:7: note: candidates are: bool operator==(const Sommet&, const Sommet&)
Thanks !
EDIT
This is how i used std::count() :
for(vector<Sommet>::iterator iter = m_sommets.begin();
iter != s_iter_end; iter++)
{
iter->SetNbSuccesseurs(count(m_sommets.begin(), m_sommets.end(), iter));
}
It looks like you are passing in an iterator as the last parameter to std::count whereas you need to pass in a value (by const reference).
Post edit: it looks like I was correct, you are passing iter which is an iterator. You need to dereference it first. Try passing *iter instead.
What you need to pass to count is a value, not an iterator:
iter->SetNbSuccesseurs(count(m_sommets.begin(), m_sommets.end(), *iter));