Читать «Эффективный и современный С++. 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? Как связаны константные функции-члены и безопасность с точки зрения потоков? Этот список можно продолжать и продолжать. В этой главе постепенно, один за другим, даются ответы на эти вопросы.