Using own Comparator operator() for map<>. Givi

2019-08-05 07:57发布

问题:

I have tried to implement own operator and used in map<>, code looks as follows:

#include <iostream>
#include <map>
#include <string>

using namespace std;

struct keyInfo
{
  string Key1; 
  string Key2; 

  /*bool keyInfo::operator()(keyInfo const& Left,keyInfo const& Right) const{
      return ((Left.Key1<Right.Key1)&&(Left.Key2<Right.Key2));
  }*/
};

struct LessComparer{
    bool operator()(keyInfo const& Left,keyInfo const& Right) const{
        return !(Left.Key1==Right.Key1 && Left.Key2==Right.Key2);
    }
};

struct valueInfo
{ 
  int value1; 
  int value2; 
  int value3; 

  valueInfo(const int A,const int B,const int C) : 
    value1(A),value2(B),value3(C) {}
};
typedef std::map<keyInfo, valueInfo, LessComparer> MapTYPE;

int main()
{
  MapTYPE TMap;
  keyInfo K;
  K.Key1="main";
  K.Key2="i";
  valueInfo V(-2,-3322,9000);

  TMap.insert(MapTYPE::value_type(K,V));
  MapTYPE::iterator It1=TMap.find(K);
  It1=TMap.find(K);
  if(It1!=TMap.end())
    std::cout<<"Success(K): "<<It1->second.value2<<std::endl;

  keyInfo E;
  E.Key1="main";
  E.Key2="j";
  //TMap.insert(std::pair<keyInfo,valueInfo>(E,V));
  MapTYPE::iterator It2=TMap.find(E);
  if (It2!=TMap.end())
     std::cout<<"Success(E): "<<(It2->second).value3<<std::endl;

  cin.get();
  return 0;
 }

Here I'm using operator() to return 0 iff both Key1 and Key2 of Left and Right are equal. I think this is the same way map::less works, I mean it return false only if equality condition is satisfied.

It works fine in first case i.e. TMap.find(K) where same key is found. But during call in second case i.e. TMap.find(E) it pops up an error saying:

"Debug assertion failed"
Expression: Invalid operator <

回答1:

The comparison operator must define a strict weak ordering. You can generically write such a comparison for a compound of comparable types via lexicographic comparison:

define "(a1, b1) < (a2, b2)" if and only if

   (a1 < a2) OR (a1 == a2 AND b1 < b2)

This generalises to an arbitrary tuple (a1, b1, c1, ...) in the obvious way.

In C++, this should be written as follows:

return (Left.key1 < Right.key1) ||
       (!(Left.key1 > Right.key1) && (Left.key1 < Right.key1));

This way, you can define a lexicographic ordering on any tuple of types using only the existing <-operator for each constituent type. (Note that this ordering considers two elements x and y equivalent if !(x < y) && !(y < x).)