Как обнаружить неявные потери преобразования целочисленной точности на std :: vector :: emplace_back - PullRequest
1 голос
/ 19 июня 2020

Я скомпилировал следующий код с параметром компилятора -Wconversion для обнаружения потери целочисленной точности неявного преобразования:

#include <vector>
#include <cstdint>

int main() {
    std::vector<std::uint16_t> v;
    std::uint32_t a = 0;
    v.emplace_back(a);  // no warning
    v.push_back(a);     // warning: implicit conversion loses integer precision
}

Compiling Demo https://wandbox.org/permlink/K5E4sUlfGBw6C5w8

Вектор value_type равно std::uint16_t. Если I push_back std::uint32_t значение вектора, то я получил следующее предупреждение, как и ожидал.

prog.cc:8:17: warning: implicit conversion loses integer precision: 'std::uint32_t' (aka 'unsigned int') to 'std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >::value_type' (aka 'unsigned short') [-Wimplicit-int-conversion]
v.push_back(a);     // warning: implicit conversion loses integer precision
  ~~~~~~~~~ ^
1 warning generated.

Однако, если I emplace_back то же значение для вектора, предупреждения не обнаружено .

Я тестировал clang ++ 10.0.0, clang ++ 9.0.0 и g ++ 9.3.0 и получил тот же результат.

Есть ли хороший способ обнаружить неявные потери при преобразовании целых чисел точность на std :: vector :: emplace_back?

1 Ответ

1 голос
/ 19 июня 2020

При вызове v.emplace_back(a) неявного преобразования не происходит. Если бы вы вызывали v.emplace_back<const std::uint16_t &>(a).

, то произошло бы неявное преобразование. Ключевое различие между push_back и emplace_back состоит в том, что последний является шаблоном, а первый - нет. Если вы не укажете аргумент шаблона для emplace_back, компилятор выведет его из аргумента функции, что означает, что преобразование не потребуется в точке вызова. В пределах emplace_back преобразование происходит в системном заголовке, который подавляет предупреждение.

Итак, в вашем примере

v.emplace_back(a);

выводится как

v.emplace_back<const std::uint32_t &>(a);

где ожидается, что аргумент функции будет std::uint32_t. Идеальное совпадение, без необходимости преобразования за пределами системного заголовка. Если бы вы включили предупреждения в системных заголовках, вы могли бы получить кучу ложных предупреждений

Чтобы получить неявное преобразование в вашем коде, вам нужно заставить emplace_back ожидать std::uint16_t, что может быть выполнено через

v.emplace_back<const std::uint16_t &>(a);

Это неявно преобразует a в std::uint16_t перед вызовом emplace_back, вызывая предупреждение компилятора так же, как push_back.

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