简体   繁体   中英

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< , ie 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;
   }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM