Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - страница 21
Вот как наша функция >f
может выдать точную информацию о типах с использованием Boost.TypeIndex:
>#include
>template
>void f(const T& param) {
> using std::cout;
> using boost::typeindex::type_id_with_cvr;
> // Вывод информации о Т
> cout << "Т = "
> << type_id_with_cvr
> << '\n';
> // Вывод информации о типе param
> cout << "param = "
> << type_id_with_cvr
> << '\n';
>}
Как это работает? Шаблон функции >boost::typeindex::type_id_with_cvr
получает аргумент типа (тип, о котором мы хотим получить информацию) и не удаляет >const
, >volatile
или квалификатор ссылки (о чем и говорит “>with_cvr
” в имени шаблона). Результатом является объект >boost::typeindex::type_index
, функция-член >pretty_name
которого дает >std::string
с удобочитаемым представлением типа.
При такой реализации >f
обратимся вновь к вызову, который давал нам неверную информацию о типе >param
при использовании >typeid
:
>std::vector
>const auto vw = createVec(); // Инициализация vw с помощью
> // фабричной функции
>if (!vw.empty()) {
> f(&vw[0]); // Вызов f
>}
После компиляции с помощью компиляторов GNU и Clang Boost.TypeIndex дает следующий (точный) результат:
>Т = Widget const*
>param = Widget const* const&
Применение компилятора Microsoft дает по сути то же самое:
>Т = class Widget const *
>param = class Widget const * const &
Такое единообразие — это хорошо, но важно помнить, что редакторы IDE, сообщения об ошибках компилятора и библиотеки наподобие Boost.TypeIndex являются всего лишь инструментами, которые можно использовать для выяснения того, какие типы выводит ваш компилятор. Это может быть полезно, но не может заменить понимания информации о выводе типов, приведенной в разделах 1.1–1.3.
• Выводимые типы часто можно просмотреть с помощью редакторов IDE, сообщений об ошибках компиляции и с использованием библиотеки Boost.TypeIndex.
• Результаты, которые выдают некоторые инструменты, могут оказаться как неточными, так и бесполезными, так что понимание правил вывода типов в С++ является совершенно необходимым.
Глава 2
Объявление >auto
Концептуально объявление >auto
настолько простое, насколько может быть, но все же сложнее, чем выглядит. Его применение экономит исходный текст, вводимый программистом, но при этом предупреждает появление вопросов корректности и производительности, над которыми вынужден мучиться программист при ручном объявлении типов. Кроме того, некоторые выводы типов >auto
, хотя и послушно соблюдают предписанные алгоритмы, дают результаты, некорректные с точки зрения программиста. Когда такое происходит, важно знать, как привести >auto
к верному ответу, поскольку возврат к указанию типов вручную — альтернатива, которой чаще всего лучше избегать. В этой короткой главе описаны основы работы с >auto
.
2.1. Предпочитайте >auto
явному объявлению типа
Легко и радостно написать
>int x;
Стоп! #@$! Я забыл инициализировать >x
, так что эта переменная имеет неопределенное значение. Может быть. Но она может быть инициализирована и нулем — в зависимости от контекста. Жуть!
Ну, ладно. Давайте лучше порадуемся объявлению локальной переменной, инициализированной разыменованием итератора:
>template
>void dwim(It b, It e) // элементами из диапазона от b до e
>{
> while (b != e) {
> typename std::iterator_traits
> currValue = *b;
> }
>}
Жуть. >typename std::iterator_traits
— просто чтобы записать тип значения, на которое указывает итератор? Нет, я такой радости не переживу… #@$! Или я это уже говорил?..
Ладно, третья попытка. Попробую объявить локальную переменную, тип которой такой же, как у лямбда-выражения. Но его тип известен только компилятору. #@$! (Это становится привычкой…)
Да что же это такое — никакого удовольствия от программирования на С++! Так не должно быть. И не будет! Мы дождались С++11, в котором все эти проблемы решены с помощью ключевого слова >auto
. Тип переменных, объявленных как