Читать «Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14» онлайн - страница 38
Скотт Мейерс
В примере с Matrix
идиома явно типизированного инициализатора выглядит следующим образом:
auto sum = static_cast<Matrix>(m1 + m2 + m3 + m4);
Применение идиомы не ограничивается инициализаторами, производимыми прокси-классами. Она может быть полезной для того, чтобы подчеркнуть, что вы сознательно создаете переменную типа, отличного от типа, генерируемого инициализирующим выражением. Предположим, например, что у вас есть функция для вычисления некоторого значения отклонения:
double calcEpsilon(); // Возвращает значение отклонения
Очевидно, что calcEpsilon
возвращает значение double
, но предположим, что вы знаете, что для вашего приложения точности float
вполне достаточно и для вас существенна разница в размерах между float
и double.
Вы можете объявить переменную типа float
для хранения результата функции calcEpsilon
float ер = calcEpsilon(); // Неявное преобразование
// double -> float
но это вряд ли выражает мысль “я намеренно уменьшаю точность значения, возвращенного функцией”. Зато это делает идиома явной типизации инициализатора:
auto ер = static_cast<float>(calcEpsilon());
Аналогичные рассуждения применяются, если у вас есть выражение с плавающей точкой, которое вы преднамеренно сохраняете как целочисленное значение. Предположим, что вам надо вычислить индекс элемента в контейнере с итераторами произвольного доступа (например, std::vector
, std::deque
или std::array
) и вы получаете значение типа double
между 0.0
и 1.0
, указывающее, насколько далеко от начала контейнера расположен этот элемент (0.5
указывает на середину контейнера). Далее, предположим, что вы уверены в том, что полученный индекс можно разместить в int
. Если ваш контейнер — с
, а значение с плавающей точкой — d
, индекс можно вычислить следующим образом:
int index = d * (c.size() - 1);
Но здесь скрыт тот факт, что вы преднамеренно преобразуете double
справа от знака “=
” в int
. Идиома явно типизированного инициализатора делает этот факт очевидным:
auto index = static cast<int>(d * (c.size() - 1));
Следует запомнить
• “Невидимые” прокси-типы могут привести auto
к выводу неверного типа инициализирующего выражения.
• Идиома явно типизированного инициализатора заставляет auto
выводить тот тип, который нужен вам.
Глава 3
Переход к современному С++
Когда дело доходит до умных терминов, С++ 11 и С++14 есть чем похвастаться. auto
, интеллектуальные указатели, семантика перемещения, лямбда-выражения, параллелизм — каждая возможность настолько важна, что я посвящаю ей отдельную главу. Очень важно освоить все эти возможности, но большой путь к эффективному программированию на современном С++ требует множества маленьких шажков. Каждый шаг отвечает на конкретные вопросы, возникающие во время путешествия от С++98 к современному С++. Когда следует использовать фигурные скобки вместо круглых для создания объектов? Почему объявление псевдонимов лучше, чем применение typedef
? Чем constexpr
отличается от const
? Как связаны константные функции-члены и безопасность с точки зрения потоков? Этот список можно продолжать и продолжать. В этой главе постепенно, один за другим, даются ответы на эти вопросы.