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 ?
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.