《C++标准库(第2版)》【德】Nicolai M.Josuttis著,侯捷 译
这本书,第7.8.6的一个综合实例:运用Map、String并于运行期指定排序规则
该例子展现了以下技巧:
- 如何使用map,包括使用关联式数组(associative array)接口。
- 如何撰写和使用函数对象(function object)。
- 如何在运行期定义排序规则(sorting criterion)。
- 如何在“大小写无关”的情况下比较字符串(string)。
#include <iostream>
#include <iomanip>
#include <map>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;
class RuntimeStringCmp {
public:
// constants for the comparison criterion
enum cmp_mode { normal, nocase };
private:
// actual comparison mode
const cmp_mode mode;
// auxiliary function to compare case insensitive
static bool nocase_compare(char c1, char c2)
{
return toupper(c1) < toupper(c2);
}
public:
// constructor: initializes the comparison criterion
RuntimeStringCmp(cmp_mode m = normal) : mode(m) {
}
// the comparison
bool operator() (const string& s1, const string& s2) const
{
if (mode == normal)
{
return s1 < s2;
}
else
{
return lexicographical_compare(s1.begin(), s1.end(),
s2.begin(), s2.end(),
nocase_compare); //(1)会有困惑的地方
}
}
};
typedef map<string, string, RuntimeStringCmp> StringStringMap;
// function that fills and prints such containers
void fillAndPrint(StringStringMap& coll);
int main()
{
// create a container with the default comparison criterion
StringStringMap coll1;
fillAndPrint(coll1);
// create an object for case-insensitive comparisons
RuntimeStringCmp ignorecase(RuntimeStringCmp::nocase);
// create a container with the case-insensitive comparisons criterion
StringStringMap coll2(ignorecase); //(2)会有困惑的地方
fillAndPrint(coll2);
getchar();
return 0;
}
void fillAndPrint(StringStringMap& coll)
{
// fill insert elements in random order
coll["Deutschland"] = "Germany";
coll["deutsch"] = "German";
coll["Haken"] = "snag";
coll["arbeiten"] = "work";
coll["Hund"] = "dog";
coll["gehen"] = "go";
coll["Unternehmen"] = "enterprise";
coll["unternehmen"] = "undertake";
coll["gehen"] = "walk";
coll["Bestatter"] = "undertaker";
// print elements
StringStringMap::iterator pos;
cout.setf(ios::left, ios::adjustfield);
for (pos = coll.begin(); pos != coll.end(); ++pos) {
cout << setw(15) << pos->first.c_str() << " "
<< pos->second << endl;
}
cout << endl;
}
运行结果:
上面的代码中有两个地方可能会有困惑
(1)会有困惑地方
lexicographical_compare(s1.begin(), s1.end(),
s2.begin(), s2.end(),
nocase_compare); //(1)会有困惑的地方
nocase_compare这个函数是静态成员函数,如果这个nocase_compare函数是普通函数,也是可以的。
比如改成:
bool nocase_compare(char c1, char c2)
{
return toupper(c1) < toupper(c2);
}
class RuntimeStringCmp {
public:
// constants for the comparison criterion
enum cmp_mode { normal, nocase };
private:
// actual comparison mode
const cmp_mode mode;
// auxiliary function to compare case insensitive
//static bool nocase_compare(char c1, char c2)
//{
// return toupper(c1) < toupper(c2);
//}
public:
// constructor: initializes the comparison criterion
RuntimeStringCmp(cmp_mode m = normal) : mode(m) {
}
// the comparison
bool operator() (const string& s1, const string& s2) const
{
if (mode == normal)
{
return s1 < s2;
}
else
{
return lexicographical_compare(s1.begin(), s1.end(),
s2.begin(), s2.end(),
nocase_compare); //会有困惑的地方
}
}
};
其余代码保持不变,一样可以编译通过,运行结果相同。
(1)会有困惑地方
typedef map<string, string, RuntimeStringCmp> StringStringMap;
//中间省略
// create an object for case-insensitive comparisons
RuntimeStringCmp ignorecase(RuntimeStringCmp::nocase);
// create a container with the case-insensitive comparisons criterion
StringStringMap coll2(ignorecase); //(2)会有困惑的地方
查文档:
http://www.cplusplus.com/reference/map/map/map/
explicit map (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
std::map有这样的一个构造函数,就能理解了,第二个参数alloc就让它用默认值,前面的comp,传入ignorecase这个对象,就能说通了。也就通过这里控制是大小写忽略进行key值的比较。
学习完本例,就能解决了下面的问题: