缩小 C++0x 中的转换范围。是只有我这么认为,还是这听起来像是一个重大改变?
C++0x 将使以下代码和类似代码格式错误,因为它需要从 double
到 int 的所谓窄化转换
。
int a[] = { 1.0 };
我想知道这种初始化在现实世界的代码中是否经常使用。此更改会破坏多少代码?如果您的代码受到影响,需要付出很大的努力才能在代码中修复此问题吗?
有关参考,请参阅 n3225 的 8.5.4/6
缩小转换是隐式转换
- 从浮点类型到整数类型,或者
- 从long double到double或float,或者从double到float,除非源是常量表达式并且转换后的实际值在可以表示的值范围内(即使无法精确表示) ,或
- 从整数类型或无作用域枚举类型到浮点类型,除非源是常量表达式,并且转换后的实际值将适合目标类型,并且在转换回原始值时将产生原始值输入,或
- 从整数类型或无作用域枚举类型到无法表示原始类型的所有值的整数类型,除非源是常量表达式,并且转换后的实际值将适合目标类型并产生转换回原始类型时的原始值。
C++0x is going to make the following code and similar code ill-formed, because it requires a so-called narrowing conversion of a double
to a int
.
int a[] = { 1.0 };
I'm wondering whether this kind of initialization is used much in real world code. How many code will be broken by this change? Is it much effort to fix this in your code, if your code is affected at all?
For reference, see 8.5.4/6 of n3225
A narrowing conversion is an implicit conversion
- from a floating-point type to an integer type, or
- from long double to double or float, or from double to float, except where the source is a constant expression and the actual value after conversion is within the range of values that can be represented (even if it cannot be represented exactly), or
- from an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type, or
- from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
当我使用 GCC 时,我遇到了这个重大变化。编译器打印出如下代码的错误:
幸运的是,错误消息很简单,修复也很简单:
代码位于外部库中,仅在一个文件。我认为重大更改不会影响太多代码。新手可能获取 但很困惑。。
I ran into this breaking change when I used GCC. The compiler printed an error for code like this:
Fortunately, the error messages were straightforward and the fix was simple:
The code was in an external library, with only two occurrences in one file. I don't think the breaking change will affect much code. Novices might get confused, though.
如果我发现我在过去 12 年中编写的任何 C++ 代码都存在此类问题,我会对自己感到惊讶和失望。但大多数编译器都会一直发出有关任何编译时“缩小”的警告,除非我遗漏了一些东西。
这些是否也会缩小转化范围?
如果是这样,我认为它们可能比浮点类型到整数类型的示例更频繁地出现。
I would be surprised and disappointed in myself to learn that any of the C++ code I wrote in the last 12 years had this sort of problem. But most compilers would have spewed warnings about any compile-time "narrowings" all along, unless I'm missing something.
Are these also narrowing conversions?
If so, I think they might come up a bit more often than your floating-type to integral-type example.
尝试将 -Wno-narrowing 添加到您的 CFLAGS,例如:
Try adding -Wno-narrowing to your CFLAGS, for example :
我遇到的一个实际例子:
数字文字隐式为 double ,这会导致提升。
A practical instance that I have encountered:
The numeric literal is implicitly
double
which causes promotion.如果有人遇到类似的情况,我不会感到惊讶:(
在我的实现中,最后两个在转换回 int/long 时不会产生相同的结果,因此正在缩小)
我不记得了不过,写这个。仅当极限的近似值对某些事物有用时,它才有用。
这看起来至少也有点合理:
但它并不完全令人信服,因为如果我知道我恰好有两个值,为什么要把它们放在数组中而不是仅仅
float floatval1 = val1, floatval1 = val2;
?不过,动机是什么,为什么应该编译(并且可以工作,前提是精度损失在程序可接受的精度范围内),而float asfloat[] = {val1, val2};
不应该?无论哪种方式,我都会从两个整数初始化两个浮点数,只是在一种情况下,这两个浮点数恰好是聚合的成员。在非常量表达式导致缩小转换的情况下,即使(在特定实现上)源类型的所有值都可以在目标类型中表示并且可以转换回其原始值,这似乎特别严酷:
假设没有错误,大概修复方法始终是使转换显式化。除非您对宏做了一些奇怪的事情,否则我认为数组初始值设定项仅出现在接近数组类型的地方,或者至少出现在表示类型的地方,这可能依赖于模板参数。因此,即使比较冗长,转换也应该很容易。
I wouldn't be all that surprised if somebody gets caught out by something like:
(on my implementation, the last two don't produce the same result when converted back to int/long, hence are narrowing)
I don't remember ever writing this, though. It's only useful if an approximation to the limits is useful for something.
This seems at least vaguely plausible too:
but it isn't entirely convincing, because if I know I have exactly two values, why put them in arrays rather than just
float floatval1 = val1, floatval1 = val2;
? What's the motivation, though, why that should compile (and work, provided the loss of precision is within acceptable accuracy for the program), whilefloat asfloat[] = {val1, val2};
shouldn't? Either way I'm initializing two floats from two ints, it's just that in one case the two floats happen to be members of an aggregate.That seems particularly harsh in cases where a non-constant expression results in a narrowing conversion even though (on a particular implementation), all values of the source type are representable in the destination type and convertible back to their original values:
Assuming there's no bug, presumably the fix is always to make the conversion explicit. Unless you're doing something odd with macros, I think an array initializer only appears close to the type of the array, or at least to something representing the type, which could be dependent on a template parameter. So a cast should be easy, if verbose.
缩小转换错误与隐式整数提升规则相互作用很差。
我的代码有一个错误,看起来像
“产生缩小转换错误”(根据标准这是正确的)。原因是
c
和d
隐式提升为int
并且生成的int
不允许缩小范围回到初始化列表中的 char。OTOH
当然还可以(否则一切都会崩溃)。但令人惊讶的是,
如果 c 和 d 的总和小于 CHAR_MAX,则 Even 是可以的,并且编译时不会发出警告。我仍然认为这是 C++11 中的一个缺陷,但那里的人不这么认为 - 可能是因为如果不摆脱隐式整数转换(这是过去人们编写代码时的遗留物),就不容易修复就像
char a=b*c/d
一样,即使 (b*c) > CHAR_MAX) 也能正常工作,或者缩小转换错误(这可能是一件好事)。Narrowing conversion errors interact badly with implicit integer promotion rules.
I had an error with code which looked like
Which produces an narrowing conversion error (which is correct according to the standard). The reason is that
c
andd
implicitly get promoted toint
and the resultingint
isn't allowed to be narrowed back to char in an initializer list.OTOH
is of course still fine (otherwise all hell would break loose). But surprisingly, even
is ok and compiles without a warning if the sum of c and d is less than CHAR_MAX. I still think this is a defect in C++11, but the people there think otherwise - possibly because it isn't easy to fix without get rid of either implicit integer conversion (which is a relict from the past, when people wrote code like
char a=b*c/d
and expected it to work even if (b*c) > CHAR_MAX) or narrowing conversion errors (which are possibly a good thing).这确实是一个重大变化,因为此功能的现实生活经验表明,由于将 C++03 代码库移植到 C++11 的现实生活中的痛苦,gcc 在许多情况下已将范围缩小为错误警告。请参阅gcc bug 报告中的此评论:
It was indeed a breaking change as real life experience with this feature has shown gcc had turned narrowing into a warning from an error for many cases due to real life pains with porting C++03 code bases to C++11. See this comment in a gcc bug report:
看起来 GCC-4.7 不再给出缩小转换的错误,而是发出警告。
It looks like GCC-4.7 no longer gives errors for narrowing conversions, but warnings instead.