STL меньше оператора и ошибка "неправильный оператор <"

У меня есть код, который отлично компилируется в VS 10.0, но после вставки нескольких элементов на карту Заказов ниже я получаю "недопустимый оператор <" ошибка в библиотеке отладки Microsoft. Мой меньший оператор прост, просто сравнивает 8-байтовую строку char на char. У кого-нибудь есть идея, почему я получаю эту ошибку?

Спасибо, Mike

typedef struct MY_orderID_t
{
    char orderID[8];
} MY_orderID_t;

struct std::less<MY_orderID_t>
{ 
   bool operator()(const MY_orderID_t& k1, const MY_orderID_t& k2) const
   {
       for( int i=0; i < 8; i++ )
       {
           if( k1.orderID[i] < k2.orderID[i] )
           return( true );
       }
       return( false );
   }
};

std::map< MY_orderID_t, MY_order_t > Orders[5];

Ответы

Ответ 1

Я считаю, что проблема в том, что ваш метод сравнения двух MY_orderID_t не является строгим слабым порядком, тип отношения упорядочения, требуемый С++ STL. Чтобы быть строгим слабым порядком, ваш менее чем оператор должен иметь следующие четыре свойства:

  • Irreflexivity: x < x всегда false.
  • Антисимметрия: если x < y, то y < x всегда false.
  • Транзитивность: если x < y и y < z, то x < z всегда истинно.
  • Транзитивность эквивалентности: если x и y несравнимы, а y и z несравнимы, то x и z несравнимы.

В настоящий момент ваш заказ не подчиняется свойствам (2) или (3).

* Во-первых, (2) нарушается следующим образом:

(0, 4) < (2, 2) 
(2, 2) < (0, 4)

* Во-вторых, (3) нарушается, потому что

(0, 1) < (2, 0) < (-1, 1)

// but 

(0, 1) < (-1, 1) // Fail

Чтобы исправить это, вместо использования сравнения, которое у вас есть, вместо этого используйте лексикографическое сравнение, как этот

return std::lexicographical_compare(k1.orderID.begin(), k1.orderID.end(),
                                    k2.orderID.begin(), k2.orderID.end());

Это сравнение является строгим слабым порядком и используется по умолчанию всеми контейнерами STL. Переключение на это сравнение подчиняется свойствам (1) - (4) и должно заставить все работать правильно.

Надеюсь, это поможет!

Ответ 2

@templatetypedef сообщает вам, что не так с вашей текущей версией.

Здесь гораздо более читаемое исправление:

struct MY_orderID_type
{
    char orderID[8];
    bool operator<(const MY_orderID_type& other) const
    { return memcmp(orderID, other.orderID, 8) < 0; }
};

std::map< MY_orderID_type, MY_order_type > Orders;

Ответ 3

@templatetypedef отвечает требованиям для std::less специализации, которая будет использоваться с map, с чисто синтаксической точки зрения:

  • Вам нужно #include <functional> и <map>

  • Вам не хватает } между char orderID[8]; и MY_orderID_t; в следующей строке.

  • и

    struct std::less<MY_orderID_t>
    {
         /* ... */
    };
    

    должен быть:

    namespace std {
    template <>
    struct less<MY_orderID_t>
    {
        /* ... */
    };
    }
    

Ответ 4

Помимо любых других возможных ошибок, которые я не вижу на данный момент, эта конструкция не допускается:

struct std::less<MY_orderID_t>
{ /**/ }

std::less уже является типом, поэтому вы не можете переопределить его как другой тип.