C ++ 0x сделает следующий код и аналогичный код некорректным, поскольку он требует так называемого сужающего преобразования a double
в a int
.
int a[] = { 1.0 };
Мне интересно, часто ли этот вид инициализации используется в реальном коде. Сколько кода будет нарушено этим изменением? Сложно ли исправить это в вашем коде, если он вообще затронут?
Для справки см. 8.5.4 / 6 в n3225.
Сужающее преобразование - это неявное преобразование
- от типа с плавающей запятой к целочисленному типу или
- от long double до double или float, или от double до float, за исключением случаев, когда источник является постоянным выражением, а фактическое значение после преобразования находится в пределах диапазона значений, которые могут быть представлены (даже если оно не может быть представлено точно), или
- из целочисленного типа или типа перечисления без области действия в тип с плавающей точкой, за исключением случаев, когда источник является постоянным выражением, а фактическое значение после преобразования будет соответствовать целевому типу и даст исходное значение при преобразовании обратно в исходный тип, или
- из целочисленного типа или типа перечисления без области действия в целочисленный тип, который не может представлять все значения исходного типа, за исключением случаев, когда источник является постоянным выражением, а фактическое значение после преобразования будет соответствовать целевому типу и даст исходное значение, когда преобразован обратно в исходный тип.
c++
c++11
survey
aggregate-initialization
Йоханнес Шауб - litb
источник
источник
0
уже вint
любом случае.){
инициализаторах фигурных скобок}
, и единственное устаревшее их использование - для массивов и структур POD. Кроме того, если в существующем коде есть явные приведения, которые им принадлежат, он не сломается.int a = 1.0;
все еще в силе.Ответы:
Я столкнулся с этим критическим изменением, когда использовал GCC. Компилятор напечатал ошибку для такого кода:
void foo(const unsigned long long &i) { unsigned int a[2] = {i & 0xFFFFFFFF, i >> 32}; }
К счастью, сообщения об ошибках были простыми, и исправить было несложно:
void foo(const unsigned long long &i) { unsigned int a[2] = {static_cast<unsigned int>(i & 0xFFFFFFFF), static_cast<unsigned int>(i >> 32)}; }
Код находился во внешней библиотеке, всего два экземпляра в одном файле. Я не думаю, что критическое изменение сильно повлияет на код. Новичкам может получить путают, хотя.
источник
Я был бы удивлен и разочарован, узнав, что любой код C ++, который я написал за последние 12 лет, имеет такого рода проблемы. Но большинство компиляторов выдавали бы предупреждения о любых «сужениях» времени компиляции, если я чего-то не упускаю.
Это тоже сужает конверсию?
unsigned short b[] = { -1, INT_MAX };
Если это так, я думаю, что они могут возникать немного чаще, чем ваш пример с плавающим типом в интегральный тип.
источник
Не удивлюсь, если кого-нибудь поймают на словах вроде:
float ra[] = {0, CHAR_MAX, SHORT_MAX, INT_MAX, LONG_MAX};
(в моей реализации последние два не дают одинакового результата при преобразовании обратно в 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 }
но это не совсем убедительно, потому что, если я знаю, что у меня есть ровно два значения, зачем помещать их в массивы, а не просто
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?
Предполагая, что ошибки нет, по-видимому, исправление всегда заключается в явном преобразовании. Если вы не делаете что-то странное с макросами, я думаю, что инициализатор массива появляется только близко к типу массива или, по крайней мере, к чему-то, представляющему тип, который может зависеть от параметра шаблона. Так что гипсовая повязка должна быть простой, хотя и многословной.
источник
Практический пример, с которым я столкнулся:
float x = 4.2; // an input argument float a[2] = {x-0.5, x+0.5};
Числовой литерал является неявным,
double
что вызывает продвижение.источник
float
письменно0.5f
. ;)float
был параметр typedef или шаблона (по крайней мере, без потери точности), но дело в том, что написанный код работал с правильной семантикой и стал ошибкой с C ++ 11. Т.е. определение «критического изменения».Попробуйте добавить -Wno-сужение к своим CFLAGS, например:
CFLAGS += -std=c++0x -Wno-narrowing
источник
Ошибки сужающего преобразования плохо взаимодействуют с неявными целочисленными правилами продвижения.
У меня была ошибка с кодом, который выглядел как
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) или сужение ошибок преобразования (что, возможно, хорошо).источник
unsigned char x; static unsigned char const m = 0x7f; ... unsigned char r = { x & m };
<- сужение преобразования внутри {}. В самом деле? Итак, оператор & также неявно преобразует символы без знака в int? Ну, мне все равно, результат по-прежнему гарантированно будет беззнаковым символом, argh.Это было действительно критическое изменение, поскольку реальный опыт использования этой функции показал, что gcc превратил сужение в предупреждение об ошибке во многих случаях из-за реальных проблем с переносом баз кода C ++ 03 на C ++ 11. См. Этот комментарий в отчете об ошибке gcc :
источник
Похоже, что GCC-4.7 больше не выдает ошибки для сужения конверсий, а вместо этого выдает предупреждения.
источник