检查以下代码:
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
。
答案 0 :(得分:14)
由于toLowerCase
,你的比较器说"aLeague" == "ALeague"
。由于(根据您的比较器)"aLeague" < "ALeague" == false
和"ALeague" < "aLeague" == false
,它们必须是等效的。将等效元素插入集合中不会做任何事情。
答案 1 :(得分:4)
当您向集合中插入任何值时,该对象将检查它是否已包含该值。您的LeagueComparator
对象会将ALeague
与该集中已有的其他两个值进行比较。它确定现有值aLeague
既不大于也不小于建议的新条目(ALeague
),因此它们必须相等,因此它不会继续插入。该集只剩下两个元素。这是提供客户比较对象的重点,因此您可以控制集合如何确定两个元素是否匹配。
答案 2 :(得分:3)
鉴于你提供的比较器,“ALeague”确实等同于“aLeague”。
给定两个值,x和y,以及小于比较器z:
答案 3 :(得分:0)
将您的LeagueComparator
替换为
class LeagueComparator
{
public:
bool operator()(const string& s1, const string& s2)
{
return toLowerCase(s1) < toLowerCase(s2) ||
!(toLowerCase(s2) < toLowerCase(s1)) && s1 < s2;
}
};