Почему сужающееся преобразование не предотвращает сбой этого map.insert () неправильного типа? - PullRequest
0 голосов
/ 30 января 2019

Фон

При вставке std::pair<uint64_t, uint64_t> в C ++ std::map<uint64_t, int> ни компилятор, ни программа не жалуются, даже если переданные значения невозможны для типа данных uint64_t.

Другими словами, сужающее преобразование из std::pair<uint64_t, uint64_t>(2, -2) не работает и по умолчанию имеет тип карты std::map<uint64_t, int>

Код

Когда я компилирую и выполняю следующий код с g++ -Wall -Wconversion -Wextra -pedantic test/test_wrong_insert.cpp && ./a.out:

#include<map>
#include<iostream>

void print_map(std::map<uint64_t, int> & m){
  std::cout << "The map is now: {";
  for (const auto & n: m){
    std::cout << '(' << n.first << ',' << n.second << ") ";
  }
  std::cout << "}\n";
}

int main(){
  std::map<uint64_t, int> m;

  auto ret = m.insert(std::pair<uint64_t, uint64_t>(2,-2));
  std::cout << "Tried to insert std::pair<uint64_t, uint64_t>(2,-2). ";
  std::cout << "Return: " << ret.second << '\n';
  print_map(m);
}

Результат

... это вывод:

Tried to insert std::pair<uint64_t, uint64_t>(2,-2). Return: 1
The map is now: {(2,-2) }

Вопрос

Почему std::pair<uint64_t,uint64_t> x{-1,-2} не выдает ошибку, и как мне заставить ее вызвать ошибку?

1 Ответ

0 голосов
/ 30 января 2019

Почему std::pair<uint64_t,uint64_t> x{-1,-2} не выдает ошибку?

Это вызвано шаблоном конструктора, который участвует в разрешении перегрузки, когда оба аргумента могут использоваться для создания объектов uint64_t(или любой другой тип, который вы создали std::pair).Это перегрузка (3) в списке std::pair конструкторов , и его вычет аргумента шаблона приводит к преобразованию, которое принимается как преднамеренное (как в auto n = uint64_t{-42}; или static_cast<uint64_t>(-42);) - следовательно, без предупреждения.Вы ничего не можете с этим поделать, поскольку параметры шаблона шаблона конструктора не могут быть заданы явно, как объяснено здесь .

[...] каксделать это причиной ошибки?

Использовать std::make_pair и не полагаться на вывод аргумента шаблона:

auto p = std::make_pair<uint64_t, uint64_t>(-42, -42);
//         Be explicit: ^^^^^^^^  ^^^^^^^^

Когда вы компилируете приведенный выше фрагмент с -Wsign-conversion (важно: -Wconversion не пойдет на это!), Он выдаст вам предупреждение (очевидно, добавьте -Werror, чтобы рассматривать это как ошибку).

Проблема с std::map::insert такая же, см.перегрузка (2) здесь .Это превращает любой пригодный для использования заданный аргумент в value_type объект и обрабатывает его так, как любое преобразование будет намерением вызывающей стороны.Интересно, что эквивалентная функция-член в std::set более ограничена.Так что это поймано:

std::set<uint64_t> s;

s.insert(-42); // complains with -Wsign-conversion
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...