Почему инициализация списка позволяет преобразовывать значения типа double в значения с плавающей запятой?

Инициализация списка (синтаксис {...}) не позволяет сужать преобразования. Например, попытка инициализации списка int i с 3.14f содержит ошибку компиляции, поскольку преобразование значений с плавающей запятой в целые числа сужается:

<source>:11:32: error: narrowing conversion of '3.1400001e+0f' from 'float' to 'int' inside { } [-Wnarrowing]
     int i{3.14f};
                ^

С учетом сказанного, почему возможно построить float f с 3.14, который имеет тип double? (Преобразование из double в float считается сужающим.) Делаем следующее:

float f{3.14};

Не содержит ошибок компиляции.


person Mário Feroldi    schedule 07.01.2018    source источник
comment
Вы уверены, что разрешены преобразования из double в float? extern double y; struct X { float f; } x{y}; ошибки для меня.   -  person    schedule 07.01.2018


Ответы (1)


В списке того, что считается сужающим преобразованием, константные выражения, соответствующие целевому типу, являются исключением. Таким образом, хотя обычно double to float сужается, когда ваш double на самом деле является литералом, это разрешено.

http://coliru.stacked-crooked.com/a/6949f04fa4a8df17


Из проекта, который у меня есть (я думаю, что он близок к С++ 14):

8.5.4 Инициализация списка
(7.2) Сужающее преобразование — это неявное преобразование...
...из long double в double или float или из double в float, за исключением случаев, когда источником является константное выражение и фактическое значение после преобразования находится в пределах диапазона значений, которые могут быть представлены (даже если оно не может быть точно представлено),

person GManNickG    schedule 07.01.2018
comment
То же самое при инициализации char значением int. - person Sid S; 07.01.2018
comment
Ничего себе, почему pi_const (в связанном коде) не считается постоянным выражением? Или это вопрос, выходящий за рамки этого? - person Mário Feroldi; 07.01.2018
comment
@MárioFeroldi: это считается константным выражением. :) pi, однако, нет. - person GManNickG; 07.01.2018
comment
@GManNickG совершенно не заметил этого! Я удалю эти комментарии через несколько минут. - person Mário Feroldi; 07.01.2018
comment
@MárioFeroldi Оставьте их здесь для других людей, у которых мог быть такой же мыслительный процесс. Они по-прежнему добавляют ценность. - person John H; 07.01.2018
comment
@MárioFeroldi Немного разъяснил пример. - person GManNickG; 07.01.2018
comment
Ничего себе, так что потеря точности разрешается. 3.14 — бесконечная двоичная дробь, поэтому (float) 3.14 != 3.14. - person Arne Vogel; 08.01.2018
comment
@ArneVogel: Да. Вы могли бы представить, что существует отдельный тип ошибки преобразования для значений с плавающей запятой, которые не соответствуют своему назначению - если бы такая вещь существовала, то для этого сужающего правила преобразования могло бы иметь смысл просто ссылаться на это правило. Однако этого правила не существует, и практически большинству разработчиков на самом деле все равно, точно ли представлен их литерал; Я считаю, что это мотивация для этого исключения из правил. - person GManNickG; 08.01.2018
comment
И, в равной степени, я думаю, что 4.14 также не может быть идеально представлен в двойном размере. Однако я не уверен, каковы критерии для подгонки с плавающей запятой. Это чисто экспоненциальный диапазон или слишком много цифр будет считаться неприемлемым? например, 1.23456789 будет иметь явно усеченную точность в float. - person Gem Taylor; 08.01.2018