在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 int
到unsigned int
{错误:缩小
(((long long unsigned int)i) >> 32)
从long long unsigned int
到unsigned 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 }; }
这会产生缩小的转换错误(根据标准这是正确的)。 原因是c
和d
隐式地被提升为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