1

I compiled the following code with -Wconversion compiler option to detect implicit conversion loses integer precision:

#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

The vector's value_type is std::uint16_t. If I push_back std::uint32_t value to the vector, then I got the following warning as I expected.

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.

However, if I emplace_back the same value to the vector, no warning is detected.

I've tested it clang++ 10.0.0, clang++ 9.0.0, and g++ 9.3.0 and got the same result.

Is there any good way to detect implicit conversion losses integer precision on std::vector::emplace_back ?

Takatoshi Kondo
  • 3,111
  • 17
  • 36
  • 1
    Does this answer your question? [Forbid integer conversion with precision loss](https://stackoverflow.com/questions/45283273/forbid-integer-conversion-with-precision-loss) – KyleKnoepfel Jun 19 '20 at 02:34
  • @KyleKnoepfel Good find. I'll go along with the duplicate flag being a better result than my answer. – JaMiT Jun 19 '20 at 02:43
  • I understand that my question is the same as https://stackoverflow.com/questions/45283273/forbid-integer-conversion-with-precision-loss. There is no marked answer the question but I understand why warning is not reported by https://stackoverflow.com/a/45300370/1922763 answer. However it is difficult to find expected warning in many spurious warnings. https://stackoverflow.com/a/62462385/1922763 gives me better solution that providing explicit template argument to emplace_back. The situation is my question is duplicated but got better answer that solves my question. How should I do? – Takatoshi Kondo Jun 19 '20 at 03:51

1 Answers1

1

There is no implicit conversion when you call v.emplace_back(a). There would be an implicit conversion if you called v.emplace_back<const std::uint16_t &>(a).

A key difference between push_back and emplace_back is that the latter is a template while the former is not. If you do not specify a template argument for emplace_back, the compiler deduces it from the function argument, which means no conversion will be necessary at the point of call. Within emplace_back the conversion happens in a system header, which suppresses the warning.

So in your example,

v.emplace_back(a);

is deduced as

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

where the function argument is expected to be a std::uint32_t. Perfect match, no conversion necessary outside the system header. If you were to enable warnings within system headers, you could end up with a bunch of spurious warnings

To get an implicit conversion in your code, you need to force emplace_back to expect a std::uint16_t, which can be done via

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

This would implicitly convert a to std::uint16_t before calling emplace_back, triggering the compiler warning in the same way that push_back does.

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • Thank you for the answer! I didn't come up with explicit template argument approach. I reported the problem to GCC bugzilla https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95765 . The report marked as duplicated but Jonathan Wakely fixed the warnings in the libstdc++. Before the fix https://godbolt.org/z/jmkc5W after the fix https://godbolt.org/z/9TmShD. Noisy warnings are disappeared. Maybe this is just one part of standard library warning problems but it has actually been improved. – Takatoshi Kondo Jun 20 '20 at 10:12