缩小C++ 0x中的转换.它只是我,还是听起来像一个突破性的变化?

Joh*_*itb 82 c++ survey aggregate-initialization c++11

的C++ 0x将会使下面的代码和类似代码形成不良的,因为它需要一个所谓的收缩转换double一个int.

int a[] = { 1.0 };
Run Code Online (Sandbox Code Playgroud)

我想知道这种初始化是否在现实代码中被大量使用.这个改变将破坏多少代码?如果您的代码受到影响,是否需要在代码中修复此问题?


供参考,参见n3225的8.5.4/6

缩小转换是隐式转换

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

Tim*_*003 41

当我使用GCC时,我遇到了这个突破性的变化.编译器为这样的代码打印了一个错误:

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

功能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内的转换{}

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

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

代码位于外部库中,一个文件中只出现两次.我不认为突破性的变化会影响很多代码.但是,新手可能 感到困惑.


asc*_*ler 9

我会对自己感到惊讶和失望,因为我知道我在过去12年中编写的任何C++代码都有这样的问题.但是大多数编译器都会对任何编译时间的"缩小"发出警告,除非我遗漏了什么.

这些也缩小了转换次数吗?

unsigned short b[] = { -1, INT_MAX };
Run Code Online (Sandbox Code Playgroud)

如果是这样的话,我认为它们可能会比你的浮点型到积分式的例子更频繁.


Ste*_*sop 7

如果有人被这样的事情搞得一团糟,我不会感到惊讶:

float ra[] = {0, CHAR_MAX, SHORT_MAX, INT_MAX, LONG_MAX};
Run Code Online (Sandbox Code Playgroud)

(在我的实现中,最后两个在转换回int/long时不会产生相同的结果,因此变窄)

不过,我不记得曾写过这篇文章.只有当极限的近似对某些东西有用时,它才有用.

这似乎至少含糊不清:

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
}
Run Code Online (Sandbox Code Playgroud)

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

在非常量表达式导致转换变窄的情况下,这似乎特别苛刻,即使(在特定实现中),源类型的所有值都可在目标类型中表示并可转换回其原始值:

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

假设没有错误,可能修复总是使转换显式化.除非你对宏做了一些奇怪的事情,我认为数组初始化程序只出现在数组类型附近,或者至少表示类型的东西,这可能依赖于模板参数.如果详细,那么演员应该很容易.

  • *"如果我知道我有两个值,为什么要将它们放在数组中"* - 例如因为像OpenGL这样的API需要它. (8认同)

Jed*_*Jed 5

我遇到的一个实际例子:

float x = 4.2; // an input argument
float a[2] = {x-0.5, x+0.5};
Run Code Online (Sandbox Code Playgroud)

数字文字隐含地double导致促销.

  • 因此,通过编写“0.5f”使其成为“浮动”。;) (2认同)
  • @underscore_d 如果 `float` 是一个 typedef 或模板参数,则不起作用(至少没有损失精度),但关键是编写的代码使用正确的语义,并在 C++11 中成为错误。即,“重大变更”的定义。 (2认同)

小智 5

尝试将-Wno-narrowing添加到CFLAGS中,例如:

CFLAGS += -std=c++0x -Wno-narrowing
Run Code Online (Sandbox Code Playgroud)