Читать «Эффективный и современный С++. 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.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
с удобочитаемым представлением типа.