Читать «Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14» онлайн - страница 28

Скотт Мейерс

К сожалению, результат std::type_info::name ненадежен. Например, в данном случае тип, который все три компилятора приписывают param, является неверным. Кроме того, он по сути обязан быть неверным, так как спецификация std::type_info::name разрешает, чтобы тип рассматривался как если бы он был передан в шаблонную функцию по значению. Как поясняется в разделе 1.1, это означает, что если тип является ссылкой, его “ссылочность” игнорируется, а если тип после удаления ссылочности оказывается const (или volatile), то соответствующие модификаторы также игнорируются. Вот почему информация о типе param — который на самом деле представляет собой const Widget* const& — выводится как const Widget*. Сначала удаляется ссылочность, а затем у получившегося указателя удаляется константность.

Не менее печально, что информация о типе, выводимая редакторами IDE, также ненадежна — или как минимум ненадежно полезна. Для этого же примера мой редактор IDE сообщает о типе Т как (я не придумываю!):

const

std::_Simple_types<std::_Wrap_alloc<std::_Vec_base_types<Widget,

std::allocator<Widget> >::_Alloc>::value_type>::value_type *

Тот же редактор IDE показывает, что тип param следующий:

const std::_Simple_types<...>::value_type *const &

Это выглядит менее страшно, чем тип Т, но троеточие в средине типа сбивает с толку, пока вы не поймете, что это редактор IDE попытался сказать “Я опускаю все, что является частью типа T”. Ваша среда разработки, быть может, работает лучше моей — если вы достаточно везучий.

Если вы склонны полагаться на библиотеки больше, чем на удачу, то будете рады узнать, что там, где std::type_info::name и IDE могут ошибаться, библиотека Boost TypeIndex (часто именуемая как Boost.TypeIndex) приведет к успеху. Эта библиотека не является частью стандарта С++, но точно так же частью стандарта не являются ни IDE, ни шаблоны наподобие рассмотренного выше TD. Кроме того, тот факт, что библиотеки Boost (доступные по адресу boost.org) являются кроссплатформенными, с открытым исходным кодом и с лицензией, разработанной так, чтобы быть приемлемой даже для самых параноидальных юристов, означает, что код с применением библиотек Boost переносим практически так же хорошо, как и код, основанный на стандартной библиотеке.

Вот как наша функция f может выдать точную информацию о типах с использованием Boost.TypeIndex:

#include <boost/type_index.hpp>

template<typename Т>

void f(const T& param) {

 using std::cout;

 using boost::typeindex::type_id_with_cvr;

 // Вывод информации о Т

 cout << "Т = "

      << type_id_with_cvr<T>().pretty_name()

      << '\n';

 // Вывод информации о типе param

 cout << "param = "

      << type_id_with_cvr<decltype(param)>().pretty_name()

      << '\n';

}

Как это работает? Шаблон функции boost::typeindex::type_id_with_cvr получает аргумент типа (тип, о котором мы хотим получить информацию) и не удаляет const, volatile или квалификатор ссылки (о чем и говорит “with_cvr” в имени шаблона). Результатом является объект boost::typeindex::type_index, функция-член pretty_name которого дает std::string с удобочитаемым представлением типа.