Перегрузка оператора сравнения в C ++ приводит к «недопустимому оператору <» - PullRequest
7 голосов
/ 26 апреля 2011

В настоящее время пытается отсортировать вектор объекта, где каждый объект содержит строку, в C ++

Строки могут содержать буквы или цифры (из-за конструктивных ограничений это необходимо, поскольку компаратор может быть изменен).

В настоящий момент класс объекта перегружен, поэтому при сравнении двух объектов сравниваются содержащиеся в них строки. Это работает до некоторой степени - однако, когда я использую операцию сортировки (такую ​​как сортировка STL), чтобы упорядочить объекты, она будет сортировать три строки, такие как «1», «4», «12», в порядке «1», «12», «4». 4 больше 12, но поскольку он начинает сравниваться с самой левой цифры, происходит «неправильная» сортировка.

Мой первоначальный ответ состоял в том, чтобы изменить способ перегрузки операции сравнения. Сначала я бы проверил длину сравниваемой строки - что было бы контрольным знаком, если бы содержимое строки было больше или меньше.

// overloaded comparision operators
friend bool operator<(const nodeRecord & record1, const nodeRecord & record2){
    // we need to deal with strings of different lengths...
    if(record1.comparator.length() < record2.comparator.length())
        return true;
    else
        return (record1.comparator < record2.comparator);
}

Эта операция приводит к появлению сообщения «Выражение: недопустимый оператор <» во время выполнения. </p>

Есть идеи, где я совершаю ошибку? Кажется, что я должен быть в состоянии диктовать операции точно, как я хочу, чтобы операция сортировки происходила - даже если она недопустима, поскольку в настоящее время я использую вектор для хранения объектов.

Компаратор при инициализации объекта nodeRecord:

nodeRecord(int fromNode, int toNode, int connectionCost, bool compareByCost = false){
    // take the provided stock information and insert it into the object
    stringstream fromNodeSS;
    fromNodeSS << fromNode;
    this->fromNode = fromNodeSS.str();
    stringstream toNodeSS;
    toNodeSS << toNode;
    this->toNode = toNodeSS.str();
    this->connectionCost = connectionCost;

    // set the comparator to our chosen comparision term
    if (!compareByCost){
        this->comparator = this->fromNode; // we use from node in this case, since we build the tree outwards
    }
    else{
        stringstream ss;
        ss << this->connectionCost;
        this->comparator = ss.str(); // we use the connection cost in this case, to allow us to sort new connections
    }

    // set this as a non-null (active) record
    this->nullRecord = false;
}

Ответы [ 3 ]

10 голосов
/ 26 апреля 2011

Ваш оператор недействителен.

Оператор < должен иметь ряд математических свойств, если вы хотите, чтобы его можно было использовать для сортировки. Одним из них является свойство Антисимметрия:

x < y => !(y < x)

Давайте определим x = "b" и y = "aa".

  • x < y потому что длина "b" уступает длине "aa"
  • y < x потому что "aa" уступает "b"

Гул?

Также обратите внимание, что ваше определение странно для чисел, если они начинаются с 0 s.

Да, и сравнение строк намного медленнее, чем сравнение чисел.

Мой дубль? Прекратите изменять узел с информацией сравнения. Фактический режим сравнения не имеет ничего общего с самим узлом.

Тогда вы просто напишите два метода сравнения, один из которых сравнивает по стоимости, а другой по происхождению.


И если вернуться к исходной проблеме, как написать компаратор, который считает ["a", "b", "aa"] отсортированным?

Вы были почти там, но сравнение "длины" является неполным. Вам нужно вернуться к фактическому лексическому сравнению только в случае, если длины различаются, поэтому вы забыли случай, когда длина аргумента в правой части меньше, чем в левой части.

Таким образом, правильная форма, если предположить две строки:

bool compare(std::string const& lhs, std::string const& rhs) {
  if (lhs.length() < rhs.length()) { return true; }
  if (rhs.length() < lhs.length()) { return false; } // don't forget this
  return lhs < rhs;
}
1 голос
/ 26 апреля 2011

Нашел следующий фрагмент кода, который выдавал ошибку, затем подумал о том, как работает моя перегруженная операция.

template<class _Ty1, class _Ty2> inline
    bool _Debug_lt(_Ty1& _Left, _Ty2& _Right,
        _Dbfile_t _File, _Dbline_t _Line)
    {   // test if _Left < _Right and operator< is strict weak ordering
    if (!(_Left < _Right))
        return (false);
    else if (_Right < _Left)
        _DEBUG_ERROR2("invalid operator<", _File, _Line);
    return (true);
    }

Это рабочее решение (снова изменено благодаря комментариям, оставленным Мэтью М).

// overloaded comparision operators
friend bool operator<(const nodeRecord & record1, const nodeRecord & record2){
    // we need to deal with strings of different lengths...
    if(record1.comparator.length() > record2.comparator.length()
        && (record1.comparator.length() !=0 && record2.comparator.length() != 0))
        return false;
    else if(record1.comparator.length() < record2.comparator.length()
        && (record1.comparator.length() !=0 && record2.comparator.length() != 0))
        return true;
    else
        return (record1.comparator < record2.comparator);
}

Спасибо всем, кто помог!

0 голосов
/ 26 апреля 2011

Почему бы вам не использовать один компаратор и сделать эту функцию немного умнее?Сделайте так, чтобы он проверял числовые символы в начале, если это так, сделайте пару strtol() или atoi() и сравните результаты.

В противном случае сравните длину строки и символов в соответствии с вашим нечисловымтребования.

...