std :: map с предикатом и списком инициализации - PullRequest
0 голосов
/ 23 сентября 2018

У меня есть 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 голосов
/ 23 сентября 2018

Потому что порядок пар в каждом случае разный.В первом случае конструктор 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"перед" Джоном ", поэтому" ДЖОН "вставляется, но во втором случае все наоборот.

0 голосов
/ 23 сентября 2018

Предикат определяет только порядок элементов, но не изменяет элементы.То, что вы получаете один раз JOHN и один раз John, просто случайно.На вашей первой карте сначала появляется 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";

Тогда карта будет содержать значения «один» и «одиннадцать», но если вы поменяете местами порядок

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

, вы получите «четыре» и «одиннадцать».

0 голосов
/ 23 сентября 2018

Заказ имеет значение здесь.Если вы переключите 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"),
};

dueДля упорядочения клавиш ваша клавиша "JOHN" ставится в качестве первой клавиши (перед клавишей "John").Теперь, если вы попытаетесь использовать той самой карты для инициализации второй, она сначала вставит пару ("JOHN", "2345765"), а затем увидит пару ("John", "2345764").Он не учитывает регистр, сравнивает ключи и выясняет, что они эквивалент , поэтому не будет вставлять строчную "John" пару.

Итак, подведем итог, это не совсем использованиеконструкторов.Это удивительное сочетание вашего заказа предоставленных пар и последовательности ключей, которые не совпадают.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...