std :: map的谓词与初始化列表

时间:2018-09-23 16:05:50

标签: c++ stl

我有一个带有自定义谓词的std::map<string, string>

struct PredIgnoreCase {
  bool operator()(const std::string& str1, const std::string& str2) const {
    std::string str1NoCase(str1), str2NoCase(str2);
    std::transform(str1.begin(), str1.end(), str1NoCase.begin(), tolower);
    std::transform(str2.begin(), str2.end(), str2NoCase.begin(), tolower);

    return (str1NoCase < str2NoCase);
  }
};

现在给予

typedef std::map<std::string, std::string> DIRECTORY_WITHCASE;
typedef std::map<std::string, std::string, PredIgnoreCase> DIRECTORY_NOCASE;

我初始化

 // Case-sensitive directory: case of string-key plays no role
  DIRECTORY_WITHCASE dirCaseSensitive{
      make_pair("John", "2345764"),
      make_pair("JOHN", "2345765"),
      make_pair("Sara", "42367236"),
      make_pair("Jack", "32435348"),
  };

然后当我初始化时

  DIRECTORY_NOCASE dirCaseInsensitive(dirCaseSensitive.begin(),
                                      dirCaseSensitive.end());

dirCaseInsensitive打印

Jack - >32435348
JOHN - >2345765 <---- John in upper case
Sara - >42367236

但是,如果我像这样初始化dirCaseInsensitive

DIRECTORY_NOCASE dirCaseInSensitive{
      make_pair("John", "2345764"),
      make_pair("JOHN", "2345765"),
      make_pair("Sara", "42367236"),
      make_pair("Jack", "32435348"),
  };

它输出正确的地图:

Jack - >32435348
John - >2345764 <----- John in lower case
Sara - >42367236

为什么同一张图的不同构造函数会给出不同的结果?

3 个答案:

答案 0 :(得分:4)

这里的订购很重要。如果您在make_pair("JOHN", "2345765")结构中将make_pair("John", "2345764")dirCaseInSensitive切换,您将看到第一个输出。

这里的情况是您第一次创建时:

DIRECTORY_WITHCASE dirCaseSensitive{
      make_pair("John", "2345764"),
      make_pair("JOHN", "2345765"),
      make_pair("Sara", "42367236"),
      make_pair("Jack", "32435348"),
};

由于键的排序,您的"JOHN"键被放置为第一个键(在"John"键之前)。现在,如果您尝试使用那个地图来初始化第二个地图,它将首先插入("JOHN", "2345765")对,然后查看("John", "2345764")对。它将不区分大小写地比较键并确定它们是等效的,因此不会插入小写的"John"对。

因此,总而言之,它实际上不是构造函数的用法。这是您所提供的对的顺序和它们的键顺序(不匹配)的令人惊讶的组合。

答案 1 :(得分:2)

因为每种情况下的配对顺序都不同。在第一种情况下,dirCaseInsensitive的构造函数(实际上)被按此顺序对进行调用。

  make_pair("JOHN", "2345765"),
  make_pair("Jack", "32435348"),
  make_pair("John", "2345764"),
  make_pair("Sara", "42367236"),

这是dirCaseSensitive中的对的顺序(假设ASCII或类似字符集)。

在第二种情况下,dirCaseInsensitive的构造函数按初始化程序列表指定的顺序成对调用。

  make_pair("John", "2345764"),
  make_pair("JOHN", "2345765"),
  make_pair("Sara", "42367236"),
  make_pair("Jack", "32435348"),

因此,您可以在第一种情况下看到“ JOHN”在“ John”之前,因此插入了“ JOHN”,但是在第二种情况下,情况正好相反。

答案 2 :(得分:1)

谓词仅定义元素的排序方式,但不修改元素。您偶然获得JOHNJohn一次。在您的第一张地图中,JOHN首先出现,因此当您使用

DIRECTORY_NOCASE dirCaseInsensitive(dirCaseSensitive.begin(),
                                    dirCaseSensitive.end());

然后JOHN将首先插入,然后John被您的谓词视为等同。

如果您这样初始化它:

DIRECTORY_NOCASE dirCaseInSensitive{
     make_pair("John", "2345764"),
     make_pair("JOHN", "2345765"),
     make_pair("Sara", "42367236"),
     make_pair("Jack", "32435348"),
};

然后首先插入John,因为JOHN被视为同一键,因此不在映射中。

谓词不会修改元素(它们以const&的形式传递),而只是控制先出现哪些元素以及哪些元素等效。如果您希望由于谓词而使用小写字母表示所有名称,那么这是错误的。如果仅插入大写字母名称,则地图将仅包含大写字母名称。

为说明这里发生的情况,请考虑一个映射,该映射在将数字作为键进行比较时会忽略最低有效数字。之后:

rounded_map[1] = "one";
rounded_map[4] = "four";
rounded_map[11] = "eleven";

然后,地图将包含值“ one”和“十一”,但是如果您交换订单

rounded_map[4] = "four";
rounded_map[1] = "one";
rounded_map[11] = "eleven";

您将获得“四个”和“十一”。