我们的代码库中有一个现有函数,如下所示:
template <class OLD_TYPE,class NEW_TYPE>
bool ConvertFromToIsValid(const OLD_TYPE fromValIC, NEW_TYPE & toValOR) noexcept
{
// Convert to new type
toValOR = static_cast<NEW_TYPE> (fromValIC);
// Convert back to OLD type and return true if there was no loss of
// information.
return( static_cast<OLD_TYPE> (toValOR) == fromValIC );
} // end ConvertFromToIsValid()
前提是如果该值可以转换为目标类型,则会返回
true
。该代码实际上并未在我们的代码库中的任何地方使用。但我只是尝试使用它,并没有达到预期的效果。
我将其放入godbolt中,发现在-O0时,它按预期工作。在-O1 处,它似乎根本无法正确运行。在 -O2 及更高版本时,它完全优化了对此函数的调用。
我刚刚尝试仔细阅读语言规范。我找不到任何地方指定这将是未定义的行为。
具体来说,我希望
UINT64_MAX
(作为 uint64_t 传递)不能在不损失精度的情况下转换为 double
。但它应该与 long double
一起使用(至少与 x64 的 clang 一起使用)。
我假设 -O0 和 -O2 之间的行为变化表明它是未定义的行为。但就像我说的,我在语言规范中找不到它的说明。
是的,如果在从浮点类型到整型类型的转换中浮点值超出整型类型的范围,则行为未定义。
如果我假设四舍五入到最接近,那就是这种情况,因为
double
可以准确地表示 2**64
并且它是最接近 2**64-1
的可表示值(即测试中的 std::numeric_limits但这与
static_cast
无关。这同样适用于隐式转换。