如何检测 std::vector::emplace_back 上的隐式转换损失整数精度

How to detect implicit conversion losses integer precision on std::vector::emplace_back

我使用 -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
}

编译演示https://wandbox.org/permlink/K5E4sUlfGBw6C5w8

矢量的 value_typestd::uint16_t。 如果我将 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.

但是,如果我 emplace_back 向量的值相同,则不会检测到警告。

我测试了 clang++ 10.0.0、clang++ 9.0.0 和 g++ 9.3.0,得到了相同的结果。

有什么好的方法可以检测 std::vector::emplace_back 上的隐式转换损失整数精度吗?

调用v.emplace_back(a)时没有隐式转换。如果你调用 v.emplace_back<const std::uint16_t &>(a).

就会有一个隐式转换

push_backemplace_back 之间的一个主要区别是后者是模板,而前者不是。如果您没有为 emplace_back 指定模板参数,编译器会从函数参数中推导出它,这意味着在调用时不需要转换。在 emplace_back 中,转换发生在系统 header 中,从而抑制了警告。

所以在你的例子中,

v.emplace_back(a);

推导为

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

函数参数应为 std::uint32_t。完美匹配,系统外无需转换header。如果您要在系统 header 中启用警告,您最终可能会收到一堆虚假警告

要在您的代码中进行隐式转换,您需要强制 emplace_back 期待 std::uint16_t,这可以通过

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

这会在调用 emplace_back 之前隐式地将 a 转换为 std::uint16_t,以与 push_back 相同的方式触发编译器警告。