Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use overloaded std::less for std::map

Tags:

c++

stl

I have the following snippet:

typedef char OR[12];

class COR
{
   OR m_or;
public:
   COR(const char* or) { strcpy(m_or, or); }
   COR(const COR& o) { strcpy(m_or, o.m_or); }
   const char* GetOR() const { return m_or; }

#if 0 // I do not wish to use this as it will create a temporary object
   bool operator<(const COR& left, const COR& right) const 
   { return (strcmp(left.m_or, right.m_or) < 0); }
#endif
};

namespace std {
   template<>
   struct less<COR> {
       bool operator()(const COR& cor, const char* or) const 
       { return (strcmp(cor.GetOR(), or) < 0); }
   };
}

When I try this I get an error: error: no matching function for call to std::map<COR, SomeStruct*, std::less<COR>, std::allocator<std::pair<const COR, SomeStruct*> > >::find(const char*&)

I do not want to use any method that involves comparison of two "COR" objects. I will have comparison of COR with const char*. Can you guys suggest a way to do it?

like image 570
abhijit Avatar asked Mar 24 '12 05:03

abhijit


People also ask

Does std::map use == operator?

std::relational operators (map) The equality comparison ( operator== ) is performed by first comparing sizes, and if they match, the elements are compared sequentially using operator== , stopping at the first mismatch (as if using algorithm equal ).

What is std :: less?

The std::less is a is a member of the functional class (<functional. h>) used for performing comparisons. It is defined as a function object class for less than inequality comparison which returns a boolean value depending upon the condition.

Are maps in C++ slow?

Maps are 'fast enough' but not brilliant for some cases. Try to analyze what is the structure of objects you need to store. If the fields are fixed I'd recommend not to use nested maps. At all.

Is std::map ordered?

Yes, a std::map<K,V> is ordered based on the key, K , using std::less<K> to compare objects, by default.


2 Answers

Several methods:
Note: None of these generate extra copies as the values are always passed by reference (and since we don't normally mutate an object on comparison pass by const reference).

Method 1:

class COR
{
   public:
   // 1: Make it a member function
   //    Thus you only specify the right hand side.
   //    The left is implicit.
   bool operator<(COR const& right) const 
   {
       return (strcmp(m_or, right.m_or) < 0);
   }
};

method 2:

class COR
{
   public:
   // 2: Make it a friend non member function
   //    Note: Just because I declare it here does not make it part of the class.
   //          This is a separate non member function
   //          The compiler makes the destinction because of the `friened`
   friend bool operator<(COR const& left, COR const& right) 
   {
       return (strcmp(left.m_or, right.m_or) < 0);
   }
};

Method 3:

class COR
{
    public:
    // Just an example. Just need some way for the functor to access members
    //                  In a way that will allow a strict weak ordering.
    bool test(COR const& right) const {return (strcmp(m_or, right.m_or) < 0);}
};

// Define a functor.
//        This is just a class with the operator() overloaded so that it can 
//        act like a function. You can make it do whatever you like but for
//        comparisons it will be passed two members of the container (accept by const
//        reference and make sure the functor is const member and things will go well).
struct CorTest
{
    bool operator()(COR const& left, COR const& right) const
    {
        return left.test(right);
    }
};

// When you declare the set you just pass as the second template parameter.
//  (or third if it is a map)
std::set<COR, CorTest>        mySet;
std::map<COR, int, CorTest>   myMap;

The method you use will depend on situation.
In most situations I would use method (1). If there is a special sort order I needed for a one off event that I want to use with a sorted container then I would use method (3). method (2) can be used as an alternative to method (1) and in some situations is better (but you need to provide more details about usage before I would say use this).

like image 80
Martin York Avatar answered Oct 24 '22 03:10

Martin York


You got this error because you made a mistake - the arguments type of the std::less operator() must be identical. So, this works:

template <>
struct std::less<COR>
{
    bool operator()(const COR &a, const COR &b) const { return (strcmp(a.GetOR(), b.GetOR()) < 0); }
};
like image 38
mr NAE Avatar answered Oct 24 '22 04:10

mr NAE