5

检查以下代码:

string toLowerCase(const string& str) {
    string res(str);
    int i;

    for (i = 0; i < (int) res.size(); i++)
        res[i] = (char) tolower(res[i]);

    return res;
}

class LeagueComparator
{
public:
    bool operator()(const string& s1, const string& s2)
    {
        return toLowerCase(s1) < toLowerCase(s2);
    }
};

int main()
{
    set<string, LeagueComparator> leagues;
    set<string, LeagueComparator>::iterator iter;

    leagues.insert("BLeague");
    leagues.insert("aLeague");    // leagues = {"aLeague", "BLeague"}
    leagues.insert("ALeague");

    for (iter = leagues.begin(); iter != leagues.end(); iter++)
        cout << *iter << endl;

    return 0;
}

输出是:

aLeague
BLeague

这让我感到震惊。我认为(并期待)输出将是:

aLeague
ALeague
BLeague

在执行之前leagues.insert("ALeague");leagues包含"aLeague""BLeague"。我的问题是,在执行leagues.insert("ALeague");时机器为什么要处理"ALeague" == "aleague"?根据我的理解, 中没有元素"ALeague"leagues所以"ALeague"应该插入到leagues. 比较器应确定放置位置"ALeague"

提前致谢。

PS:请不要因为我使用 C 风格演员而打我。:P 我懒得打字了static_cast

4

4 回答 4

14

多亏了toLowerCase,您的比较器说"aLeague" == "ALeague"。由于(根据您的比较器)"aLeague" < "ALeague" == false"ALeague" < "aLeague" == false,它们必须是等价的。并且将等效元素插入到集合中不会做任何事情。

于 2010-10-30T05:57:10.260 回答
4

当您向集合中插入任何值时,对象会检查它是否已包含该值。您的LeagueComparator对象ALeague与集合中已有的其他两个值进行比较。它确定现有值aLeague既不大于也不小于建议的新条目 ( ALeague),因此它们必须相等,因此不会继续插入。该集合仅包含两个元素。这就是提供客户比较对象的全部意义所在,因此您可以控制该集合如何确定两个元素是否匹配。

于 2010-10-30T05:58:04.567 回答
3

鉴于您提供的比较器,“ALeague”确实等同于“aLeague”。

给定两个值,x 和 y,以及一个小于比较器 z:

  • 如果 z(x, y) 为真,则 x 小于 y
  • 如果 z(y, x) 为真,则 y 小于 x
  • 如果两者都不为真,则 x 等价于 y
  • 如果两者都是真的,那么你有一个坏了的比较器。
于 2010-10-30T05:56:59.427 回答
0

替换你LeagueComparator

class LeagueComparator
{
public:
    bool operator()(const string& s1, const string& s2)
    {
        return toLowerCase(s1) < toLowerCase(s2)   ||  
               !(toLowerCase(s2) < toLowerCase(s1))  &&  s1 < s2;
    }
};
于 2010-10-30T07:04:55.577 回答