自定义有序集给出查找"invalid operator<"(...

Custom ordered set give "invalid operator<" of find(...)

本文关键字:operator invalid lt 查找 自定义      更新时间:2023-10-16

当我试图在自定义有序集中找到元素时出现问题。

File: c:program files (x86)microsoft visual studio 10.0vcincludextree
Line: 1746
Expression: invalid operator<

我需要一组字符串,其中的元素按照我的需要排序。

比较器对象:

struct OrderComparator {
public:
    static map<string,int> valueOrder;
    bool operator()( const string lhs, const string rhs ) {
        map<string,int>::iterator resultLhs,resultRhs;
        resultLhs = valueOrder.find(lhs);
        resultRhs = valueOrder.find(rhs);
        if (resultLhs == valueOrder.end() || resultRhs == valueOrder.end())
        {
            return false;
        }
        else {
            bool result = resultLhs->second <= resultRhs->second;
            return result;
        }
    }
    static map<string,int> create_map()
    {
        map<string,int> m;
        m["A"] = 1; 
        m["B"] = 2;
        m["C"] = 3;
        m["D"] = 4;
        return m;
    }
};

比较器工作正常!

但是当我试图在集合中搜索得到提到的错误时。

typedef set<string, OrderComparator> TREESET_CMP;
...
TREESET_CMP::iterator it = myTree.find(obj); <-fails
...

如果有人能告诉我为什么会发生这种情况以及如何修复它,我会很高兴。


完整的迷你示例:

    #include "stdafx.h"
#include <string>
#include <set>
#include <map>
#include <iterator>
#include <algorithm>
using namespace std;
#include <stdio.h>
#include <tchar.h>
struct OrderComparator {
public:
    static map<string,int> valueOrder;
    bool operator()( const string lhs, const string rhs ) {
        map<string,int>::iterator resultLhs,resultRhs;
        resultLhs = valueOrder.find(lhs);
        resultRhs = valueOrder.find(rhs);
        if (resultLhs == valueOrder.end() || resultRhs == valueOrder.end())
        {
            return false;
        }
        else {
            bool result = resultLhs->second <= resultRhs->second;
            return result;
        }
    }
    static map<string,int> create_map()
    {
        map<string,int> m;
        m["A"] = 1; 
        m["B"] = 2;
        m["C"] = 3;
        m["D"] = 4;
        return m;
    }
};
map<string,int> OrderComparator::valueOrder = OrderComparator::create_map();
typedef set<string, OrderComparator> TREESET_CMP;
int _tmain(int argc, _TCHAR* argv[])
{
    TREESET_CMP myTree;
    myTree.insert("B");
    myTree.insert("C");
    myTree.insert("A");
    TREESET_CMP::const_iterator it = myTree.find("A");
    system("PAUSE");
}

你的比较没有定义严格的弱排序

严格弱排序必须具有这些不变量(引用自上面的链接)

  • 反身性 f(x, x)必须为假
  • 反对称性 f (x, y)意味着! f (y, x)
  • 动词的 f (x, y)和f (y, z)意味着f (x, z)。
  • 等价的可传递性等价(如上所述)是可传递的:如果x等价于y, y等价于z,则x等价于z。(这意味着等价实际上满足等价关系的数学定义。)

你的

至少不符合非自反性(将一个对象与自身进行比较必须为假)和反对称性(如果x小于y,则y不小于x)

基本上,<=不是一个有效的排序,因为x <= x返回true,这意味着你永远无法在集合中找到一个元素。为了找到一个元素,集合查找具有!cmp(key, element) && !cmp(element, key)属性的元素,但这永远不能用于您的排序。

最简单的修复可能是将<=更改为<,但可能存在其他问题。

您的比较器可以是:

bool operator()( const string &lhs, const string &rhs ) {
    map<string,int>::iterator resultLhs,resultRhs;
    resultLhs = valueOrder.find(lhs);
    resultRhs = valueOrder.find(rhs);
    if (resultLhs == valueOrder.end()) return false;
    if (resultRhs == valueOrder.end()) return true;
    return resultLhs->second < resultRhs->second;
}

你可以将两行替换为:

if (resultRhs == valueOrder.end()) return false;
if (resultLhs == valueOrder.end()) return true;

如果您希望在映射中不存在的字符串在此之前排序,

尝试将比较方法声明为const,并为参数使用const引用。第一个修复是确保您可以使用OrderComarator的常量版本调用方法,第二个修复是避免复制。

bool operator()( const string& lhs, const string& rhs ) const {