Noah Roth
Noah Roth

Reputation: 276

std::set comparator error: "invalid operator<"

So I created a custom Comparator for an std::set. Code as follows:

class Identifier
{
    std::string nameID;

public:
    std::string NameID() const
    {
        return this->nameID;
    }
};

class IdentifierSorter
{
    static bool icompare_pred(unsigned char a, unsigned char b)
    {
        return std::tolower(a) == std::tolower(b);
    }

    bool icompare(const std::string& a, const std::string& b)
    {
        return std::lexicographical_compare(a.begin(), a.end(),
            b.begin(), b.end(), icompare_pred);
    }

    bool operator()(const Identifier& id1, const Identifier& id2)
    {
        std::string id1n = id1.NameID();
        std::string id2n = id2.NameID();
        return icompare(id1n, id2n);
    }
};

....

std::set<Identifier, IdentifierSorter> Identifiers;

Everything works fine until I try to do this:

auto it = Identifiers.find(someIdentifier);

I get a runtime error that reads:

Program: C:\Windows\system32\MSVCP120D.dll
File: c:\program files (x86)\microsoft visual studio   12.0\vc\include\xutility
Line: 2941

Expression: invalid operator<

I'm not sure what is wrong. Did I implement the Comparator incorrectly?

Upvotes: 2

Views: 1919

Answers (2)

4pie0
4pie0

Reputation: 29744

The methods of predicate have to be public:

class IdentifierSorter
{
    public:

    static bool icompare_pred(unsigned char a, unsigned char b)
    {
        return std::tolower(a) == std::tolower(b);
    }

    bool icompare(const std::string& a, const std::string& b)
    {
        return std::lexicographical_compare(a.begin(), a.end(),
            b.begin(), b.end(), icompare_pred);
    }

    bool operator()(const Identifier& id1, const Identifier& id2)
    {
        std::string id1n = id1.NameID();
        std::string id2n = id2.NameID();
        return icompare(id1n, id2n);
    }
};

Other than that predicate should behave like std::less, that is instead of

static bool icompare_pred(unsigned char a, unsigned char b)
{
    return std::tolower(a) == std::tolower(b);
}

you want

static bool icompare_pred(unsigned char a, unsigned char b)
{
    return std::tolower(a) < std::tolower(b);
                       // ^^^
}

Upvotes: 2

Ulrich Eckhardt
Ulrich Eckhardt

Reputation: 17434

Your code doesn't work because your comparison provides something like equality, while the algorithm (lexicographical_compare) needs a relation.

return std::tolower(a) < std::tolower(b);

BTW: Look at where that error message comes from. It should tell you that the predicate is invalid. Search the web for "strict weak ordering", that should give you further hints how and why this works.

Upvotes: 2

Related Questions