Понимание универсальной и универсальной инициализации в C++

Я работаю над книгой по С++, чтобы научить себя. В книге, над которой я работаю, рассказывается об сужении с помощью преобразования типов. В нем объясняется, как число double может быть сужено до int, и говорится: «Что делать, если вы считаете, что преобразование может привести к неверным значениям?» Используйте инициализаторы {}, чтобы избежать несчастных случаев. Затем он дает очень ограниченный пример кода и имеет мало контекста:

    double x{ 2.7 }; // OK
    int y(x); //error:double -> int might narrow

Я попытался запустить некоторый код, чтобы увидеть, как он работает, но мои результаты оказались не такими, как я ожидал:

    double test {1.2};
    cout << "First Line test = " << test << '\n';
    test = 3 / 2;
    cout << "Test = " << test << '\n';

Из того, что я прочитал, у меня сложилось впечатление, что если бы я инициализировал double test версией {}, а не версией =, я бы предотвратил возможность последующего сужения переменной test до int.

Разве это не так?

Я прочитал упомянутое здесь и здесь о целочисленном делении, но мне это все еще не ясно.

Если бы я работал на C, я бы использовал приведение типов:

double test = 0.0;
test = (double)3/2;
printf("test = %f", test);

У меня сложилось впечатление, что если бы я сделал это на C++, то получилось бы то же самое:

    double test {1.2};
    test = 3 / 2;

person Chrisplusian    schedule 28.02.2021    source источник
comment
Добро пожаловать в чудесный мир целочисленного деления :) (используйте ответ во 2-м повторе для исправления)   -  person πάντα ῥεῖ    schedule 28.02.2021
comment
Мой вопрос был об инициализации с использованием {}, а не о целочисленном делении. Мне сказали, что этот вопрос закрыт, и указали на статьи, которые на самом деле не отвечали на мой вопрос. Я что-то делаю не так, когда задаю вопрос?   -  person Chrisplusian    schedule 28.02.2021
comment
Результат этого кода был усечен с 3/2 до 1. Ваш вопрос: почему?, верно? Я что-то неправильно понял? Обе связанные статьи отвечают на это. Вы можете отредактировать свой вопрос и уточнить, почему этот ответ не соответствует вашему. Это обычный курс действий здесь.   -  person πάντα ῥεῖ    schedule 28.02.2021
comment
Прошу прощения, возможно, я сделал это запутанным. Мой вопрос был больше об этом: из того, что я прочитал, у меня сложилось впечатление, что если бы я инициализировал двойной тест с помощью версии {}, а не версии =, я бы не позволил тесту переменной быть разрешенным для последующего сужения до int . Я изучал C в колледже давным-давно, поэтому C++ для меня СОВЕРШЕННО новинка. То, что я прочитал в этой книге, навело меня на мысль, что если вы инициализируете {}, то это гарантирует, что результат останется того типа, которым вы его инициализировали. Когда я проверил эту идею, она не сработала. Поэтому я спрашивал больше о части {}   -  person Chrisplusian    schedule 28.02.2021
comment
Ну, вычисление (постоянного) выражения поведения и инициализация с правильно примененными покрытиями типов — несколько противоположные вещи, не так ли?   -  person πάντα ῥεῖ    schedule 28.02.2021
comment
Извините, я уверен, что то, что я спрашиваю, может быть вам совершенно ясно, но причина, по которой я задал вопрос, заключается в том, что я не понимаю. То, на что вы мне указали, отвечает на вопросы, которых я не задавал. Это неправильный сайт для новых людей, чтобы задавать вопросы?   -  person Chrisplusian    schedule 28.02.2021
comment
Извините, я не пытаюсь ничего усложнить, я просто пытаюсь научиться программировать. Если я задаю вопросы не на том сайте (потому что он не предназначен для людей, которые не разбираются в программировании), я постараюсь найти другое место. Вы знаете сайт для новичков вроде меня?   -  person Chrisplusian    schedule 28.02.2021
comment
Ну, у вас должно быть общее представление о том, что вы на самом деле просите. Может книга не очень. Здесь мы храним список значительных: "> stackoverflow.com/questions/388242/   -  person πάντα ῥεῖ    schedule 28.02.2021
comment
Книга, которой я пользуюсь, вторая в вашем списке. Так я нашел книгу. Не хочу показаться снисходительным, но вы говорите, что у меня должно быть хорошее базовое понимание или что вы на самом деле просите? Я знаю, о чем спрашиваю, но не знаю ответа, поэтому и спрашиваю. Это действительно похоже на то, что вы, ребята, просто не хотите, чтобы вас беспокоили вопросы начального уровня.   -  person Chrisplusian    schedule 28.02.2021
comment
Конечно, мы не отказываемся от вопросов начального уровня. Я повторно открыл ваш вопрос, давайте посмотрим, сможет ли кто-нибудь дать вам лучший ответ, чем тот, который можно найти в дубликатах, которые я связал.   -  person πάντα ῥεῖ    schedule 28.02.2021
comment
Вы говорите, что считаете, что двойной переменной должно быть разрешено хранить значение 1.2, но не значение 1.0, в зависимости от того, как она была первоначально инициализирована? Или вы говорите, что считаете, что результат выражения 3/2 должен зависеть от того, как этот результат будет использоваться позже? Я пытаюсь понять, где кроется недоразумение, какая часть этого примера вам непонятна.   -  person Igor Tandetnik    schedule 01.03.2021
comment
Результатом выражения 3/2 является значение 1 типа int (независимо от того, что произойдет с этим значением дальше) в соответствии с правилами целочисленного деления. Когда это значение присваивается переменной double, оно преобразуется в double и становится 1.0. Следовательно, после присваивания test = 3/2; переменная test содержит значение 1.0 типа double. Надеюсь это поможет.   -  person Igor Tandetnik    schedule 01.03.2021
comment
@IgorTandetnik Тандетник, я думал, что читал в этой книге, что если я инициализирую двойное число с помощью нотации {}, это не позволит выполнить арифметическую операцию или повторное назначение для сужения переменной. Итак, в C я бы гарантировал, что путем приведения: double test = 0.0; тест = (двойной) 3/2; printf(тест = %f, тест); Я думал, что эта книга говорит о том, что если я инициализирую ее как: double test {0.0}, это предотвратит необходимость приведения типов/или пометит ошибку при компиляции. Это не предотвращает его, потому что он все еще усекается, поэтому я, очевидно, не следую должным образом   -  person Chrisplusian    schedule 01.03.2021
comment
Почему форма инициализации некоторой переменной влияет на результат выражения, которое даже не включает эту переменную? Опять же, значением выражения 3/2 является целое число 1, независимо от того, будет ли это значение позднее присвоено переменной типа double, переменной типа int, напечатано или просто отброшено. (double)3/2 работает, потому что литерал 3 преобразуется в double перед делением; это эквивалентно 3.0/2. Опять же, это не имеет ничего общего с переменной в левой части присваивания.   -  person Igor Tandetnik    schedule 01.03.2021
comment
Наверное, я вижу это по-другому. Вы говорите, почему форма инициализации некоторой переменной влияет на результат выражения, которое даже не включает эту переменную? Я рассматривал левый тест переменной как ввод данных из результата выражения. Формулировка, используемая в книге для объяснения того, что делает инициализатор {}, звучит так: Итак, что вам делать, если вы считаете, что преобразование может привести к неправильному значению? Используйте инициализаторы {}, чтобы избежать несчастных случаев. Это несколько расплывчато, поэтому для меня плохое значение — это значение, которое теряет точность, когда не предназначено, как в коде, который я описал выше.   -  person Chrisplusian    schedule 01.03.2021
comment
И я пытался использовать инициализаторы {}, чтобы избежать несчастных случаев. Итак, есть ли лучший способ понять, что выполняют инициализаторы {}? Я довольно много читал об этом, но все объяснения выше моей головы. Я начинаю подозревать, что в этой истории есть что-то еще, и мне нужно просто надавить и забыть об этом сейчас, в надежде, что к этому вернутся позже. Все статьи, которые я могу найти в этой книге, рассказывают о структурах, классах и других вещах, которые еще не затронуты в этой книге.   -  person Chrisplusian    schedule 01.03.2021
comment
Результатом выражения 3/1 является 1. Это не зависит от того, помещено ли оно в фигурные скобки, в круглые скобки, в квадратные скобки или без фигурных скобок.   -  person n. 1.8e9-where's-my-share m.    schedule 08.03.2021


Ответы (1)


В C++ есть разные форматы инициализации.

int x = 10; // Инициализация копирования (не очень предпочтительно)

int y = 10; // Инициализация значения/Прямая инициализация (доступна как в старом, так и в новом C++)

int z {10};//Унифицированная инициализация/Инициализация фигурных скобок/Инициализация списка (входит в состав Modern C++)

Преимущества использования унифицированной инициализации

  1. Предотвращает сужающее преобразование, как вы упомянули. Но это не единственное преимущество использования универсальной инициализации.
  2. Предотвращает Самый неприятный синтаксический анализ . Чтобы привести небольшой пример с наиболее неприятным синтаксическим анализом. Когда мы используем круглые скобки () для инициализации, может возникнуть путаница между определением переменных и определением функций. В этом случае компилятор отдает приоритет функции. Надеюсь, это будет полезно для вас, с уважением.
person east1000    schedule 08.03.2021