在C ++ 0x中缩小转换。 这只是我,还是这听起来像一个突变?

C ++ 0x将使下面的代码和类似的代码格式不正确,因为它需要一个所谓的缩小double 转换

 int a[] = { 1.0 }; 

我想知道这种初始化在现实世界的代码中是否用得很多。 有多less代码会被这个改变打破? 如果您的代码受到影响,是否需要在代码中解决这个问题?


作为参考,参见n3225的8.5.4 / 6

缩小转换是一种隐式转换

  • 从浮点型到整型,或者
  • 从long double到double或float,或者从double到float,除非源是常量expression式,并且转换后的实际值在可以表示的值的范围内(即使不能精确表示),或者
  • 从整数types或非范围枚举types转换为浮点types,除非源代码是常量expression式,并且转换后的实际值适合目标types,并在转换回原始types时生成原始值,或者
  • 从整数types或非范围枚举types转换为不能表示原始types的所有值的整数types,除非源代码是常量expression式,并且转换后的实际值将适合目标types,并将在产生原始值时转换回原来的types。

当我使用GCC时遇到了这个突变。 编译器打印这样的代码错误:

 void foo(const unsigned long long &i) { unsigned int a[2] = {i & 0xFFFFFFFF, i >> 32}; } 

在函数中void foo(const long long unsigned int&)

错误:缩小(((long long unsigned int)i) & 4294967295ull)long long unsigned intunsigned int {

错误:缩小(((long long unsigned int)i) >> 32)long long unsigned intunsigned int inside {}

幸运的是,错误信息很简单,修复很简单:

 void foo(const unsigned long long &i) { unsigned int a[2] = {static_cast<unsigned int>(i & 0xFFFFFFFF), static_cast<unsigned int>(i >> 32)}; } 

代码在外部库中,一个文件中只有两个事件。 我不认为这个重大改变会影响很多代码。 新手可能会 感到困惑,但。

如果我知道在过去的12年中我写的任何C ++代码都有这样的问题,我会感到惊讶和失望。 但是大多数编译器一直会对编译时间的“缩小”发出警告,除非我错过了一些东西。

这些也是缩小转换吗?

 unsigned short b[] = { -1, INT_MAX }; 

如果是这样,我认为他们可能会比浮点型到整型的例子多一些。

如果有人被下面这样的事情抓住,我不会感到惊讶的:

 float ra[] = {0, CHAR_MAX, SHORT_MAX, INT_MAX, LONG_MAX}; 

(在我的实现中,后两者在转换回int / long时不会产生相同的结果,因此缩小了)

虽然我不记得写这个。 只有在对某些事物的近似值有用时才有用。

这似乎至less也是模糊的:

 void some_function(int val1, int val2) { float asfloat[] = {val1, val2}; // not in C++0x double asdouble[] = {val1, val2}; // not in C++0x int asint[] = {val1, val2}; // OK // now do something with the arrays } 

但它并不完全令人信服,因为如果我知道我有两个值,为什么把它们放在数组中而不是float floatval1 = val1, floatval1 = val2; ? 然而,为什么要编译(和工作,只要精度的损失在程序的可接受精度范围内)呢,而float asfloat[] = {val1, val2}; 不应该? 无论哪种方式,我从两个整数初始化两个浮点数,只是在一种情况下,两个浮点数恰好是一个聚合的成员。

在非常量expression式导致缩小转换的情况下,即使(在特定实现上)源types的所有值在目标types中都是可表示的并且可转换回其原始值,这似乎特别苛刻:

 char i = something(); static_assert(CHAR_BIT == 8); double ra[] = {i}; // how is this worse than using a constant value? 

假设没有错误,大概修正是总是使转换明确。 除非你用macros来做一些奇怪的事情,我认为一个数组初始值设定项只会出现在数组的types上,或者至less是表示types的东西,这可能取决于模板参数。 所以如果详细的话,演员应该很容易。

缩小转换错误与隐式整数提升规则严重相互影响。

我看起来像代码的错误

 struct char_t { char a; } void function(char c, char d) { char_t a = { c+d }; } 

这会产生缩小的转换错误(根据标准这是正确的)。 原因是cd隐式地被提升为int并且不允许在初始化程序列表中将得到的int缩减回char。

OTOH

 void function(char c, char d) { char a = c+d; } 

当然还是不错的(否则所有的地狱都会破裂)。 但令人惊讶的是,甚至

 template<char c, char d> void function() { char_t a = { c+d }; } 

如果c和d的总和小于CHAR_MAX,则编译时不会发出警告。 我仍然认为这是C ++ 11中的一个缺陷,但是那里的人们却认为不是这样 – 可能是因为修改隐含的整数转换并不容易(这是过去的遗留问题,当人们编写代码时像char a=b*c/d并且期望它即使(b * c)> CHAR_MAX也行)或缩小转换错误(这可能是件好事)。

我遇到的一个实际例子:

 float x = 4.2; // an input argument float a[2] = {x-0.5, x+0.5}; 

数字文字是隐含的double ,这会导致提升。

看起来GCC-4.7不再给出缩小转换的错误,而是警告。

尝试添加-Wno-narrowing到您的CFLAGS,例如:

 CFLAGS += -std=c++0x -Wno-narrowing