![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
ExamplesBoost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 38. Boost.TypeIndex 4.1
|
![]() |
Warning |
---|---|
С RTTI могут рухнуть разные классы с одинаковыми именами в анонимном пространстве имен. Ограничения эмуляции RTTI. |
Следующий пример показывает, как может храниться информация о типе. Пример работает с RTTI и без него.
#include <boost/type_index.hpp> #include <boost/unordered_set.hpp> #include <boost/functional/hash.hpp> #include <cassert> int main() { boost::unordered_set<boost::typeindex::type_index> types; // Storing some `boost::type_info`s types.insert(boost::typeindex::type_id<int>()); types.insert(boost::typeindex::type_id<float>()); // `types` variable contains two `boost::type_index`es: assert(types.size() == 2); // Const, volatile and reference will be striped from the type: bool is_inserted = types.insert(boost::typeindex::type_id<const int>()).second; assert(!is_inserted); assert(types.erase(boost::typeindex::type_id<float&>()) == 1); // We have erased the `float` type, only `int` remains assert(*types.begin() == boost::typeindex::type_id<int>()); }
Следующий пример показывает, что<type_info
>способен хранить реальный тип, успешно пройдя через все наследования.
Пример работает с RTTI и без него».
#include <boost/type_index.hpp> #include <iostream> struct A { BOOST_TYPE_INDEX_REGISTER_CLASS virtual ~A(){} }; struct B: public A { BOOST_TYPE_INDEX_REGISTER_CLASS }; struct C: public B { BOOST_TYPE_INDEX_REGISTER_CLASS }; void print_real_type(const A& a) { std::cout << boost::typeindex::type_id_runtime(a).pretty_name() << '\n'; } int main() { C c; const A& c_as_a = c; print_real_type(c_as_a); // Outputs `struct C` print_real_type(B()); // Outputs `struct B` }
Следующий пример показывает, что<type_index
>(и<type_info
>) способен хранить точный тип, без стриптиза, летучих и ссылок. Пример работает с RTTI и без него.
В этом примере мы создадим класс, который хранит указатель для функционирования и запоминает точный тип параметра, который принимает функция. При вызове связанной функции фактический тип входного параметра проверяется на тип хранимого параметра и в случае несоответствия выбрасывается исключение.
#include <boost/type_index.hpp> #include <iostream> #include <stdexcept> #include <cassert> class type_erased_unary_function { void* function_ptr_; boost::typeindex::type_index exact_param_t_; public: template <class ParamT> type_erased_unary_function(void(*ptr)(ParamT)) : function_ptr_(reinterpret_cast<void*>(ptr)) // ptr - is a pointer to function returning `void` and accepting parameter of type `ParamT` , exact_param_t_(boost::typeindex::type_id_with_cvr<ParamT>()) {} template <class ParamT> void call(ParamT v) { if (exact_param_t_ != boost::typeindex::type_id_with_cvr<ParamT>()) { throw std::runtime_error("Incorrect `ParamT`"); } return (reinterpret_cast<void(*)(ParamT)>(function_ptr_))(v); } }; void foo(int){} int main() { type_erased_unary_function func(&foo); func.call(100); // OK, `100` has type `int` try { int i = 100; // An attempt to convert stored function to a function accepting reference func.call<int&>(i); // Will throw, because types `int&` and `int` mismatch assert(false); } catch (const std::runtime_error& /*e*/) {} }
Следующий пример показывает, как выглядят различные имена типов, когда мы явно используем классы для RTTI и RTT.
Этот пример требует RTTI. Для более портативного примера см. «Получение читабельных и искажённых имен типов»:
#include <boost/type_index/stl_type_index.hpp> #include <boost/type_index/ctti_type_index.hpp> #include <iostream> template <class T> void print(const char* name) { boost::typeindex::stl_type_index sti = boost::typeindex::stl_type_index::type_id<T>(); boost::typeindex::ctti_type_index cti = boost::typeindex::ctti_type_index::type_id<T>(); std::cout << "\t[" /* start of the row */ << "[" << name << "]" << "[`" << sti.raw_name() << "`] " << "[`" << sti.pretty_name() << "`] " << "[`" << cti.raw_name() << "`] " << "]\n" /* end of the row */ ; } struct user_defined_type{}; namespace ns1 { namespace ns2 { struct user_defined_type{}; }} // namespace ns1::ns2 namespace { struct in_anon_type{}; } // anonymous namespace namespace ns3 { namespace { namespace ns4 { struct in_anon_type{}; }}} // namespace ns3::{anonymous}::ns4 template <class T0, class T1> class templ {}; template <> class templ<int, int> {}; int main() { std::cout << "[table:id Table of names\n"; std::cout << "\t[[Type] [RTTI & raw_name] [RTTI & pretty_name] [noRTTI & raw_name]]\n"; print<user_defined_type>("User defined type"); print<in_anon_type>("In anonymous namespace"); print<ns3::ns4::in_anon_type>("In ns3::{anonymous}::ns4 namespace"); print<templ<short, int> >("Template class"); print<templ<int, int> >("Template class (full specialization)"); print<templ< templ<char, signed char>, templ<int, user_defined_type> > >("Template class with templae classes"); std::cout << "]\n"; }
Код из примера будет содержать следующую таблицу:
Table 38.2. Table of names
Тип |
RTTI & raw_name |
RTTI &: pretty_name |
noRTTI & raw_name |
---|---|---|---|
Тип пользователя |
< |
< |
< |
В анонимном пространстве имен |
< |
< |
< |
В ns3::{anonymous}::ns4 namespace |
< |
< |
< |
Класс шаблонов |
< |
< |
< |
Класс шаблонов (полная специализация) |
< |
< |
< |
Класс шаблонов с классами шаблонов |
< |
< |
< |
Мы не показываем колонку «noRTTI & pretty_name» в таблице, потому что она почти равна колонке «noRTTI & raw_name».
![]() |
Warning |
---|---|
С RTTI могут рухнуть разные классы с одинаковыми именами в анонимном пространстве имен. Ограничения эмуляции RTTI. |
Следующий пример показывает, что<boost::typeindex::ctti_type_index
>можно использовать во время компиляции на совместимых компиляторах C++14.
В этом примере мы создадим и используем функцию constexpr, которая проверяет пространство имен предоставленного типа.
#include <boost/type_index/ctti_type_index.hpp> // Helper function that returns true if `name` starts with `substr` template <std::size_t N> constexpr bool starts_with(const char* name, const char (&substr)[N]) noexcept; // Function that returns true if `T` declared in namespace `ns` template <class T, std::size_t N> constexpr bool in_namespace(const char (&ns)[N]) noexcept { const char* name = boost::typeindex::ctti_type_index::type_id<T>().raw_name(); // Some compilers add `class ` or `struct ` before the namespace, so we need to skip those words first if (starts_with(name, "class ")) { name += sizeof("class ") - 1; } else if (starts_with(name, "struct ")) { name += sizeof("struct ") - 1; } return starts_with(name, ns) && starts_with(name + N - 1, "::"); }
Теперь, когда у нас есть эта удивительная функция, мы можем делать статические утверждения и другие проверки времени компиляции:
namespace my_project { struct serializer { template <class T> void serialize(const T& value) { static_assert( in_namespace<T>("my_project::types") || in_namespace<T>("my_project::types_ext"), "Only types from namespaces `my_project::types` and `my_project::types_ext` are allowed to be serialized using `my_project::serializer`" ); // Actual implementation of the serialization goes below // ... } }; namespace types { struct foo{}; struct bar{}; } } // namespace my_project int main() { my_project::serializer s; my_project::types::foo f; my_project::types::bar b; s.serialize(f); s.serialize(b); // short sh = 0; // s.serialize(sh); // Fails the static_assert! }
Следующий пример показывает, что<boost::typeindex::ctti_type_index
>можно использовать во время компиляции на совместимых компиляторах C++14 для проверки порядка параметров шаблона.
Рассмотрим ситуацию, когда у нас есть функция, которая принимает std::tuple, boost::variant или какой-либо другой класс, использующий вариативные шаблоны:
template <class... T> class types{}; template <class... T> void do_something(const types<T...>& t) noexcept;
Такие функции могут быть очень полезными, однако они могут значительно увеличить размер полученной программы. Каждая инстанция такой функции с различным порядком шаблонов потребляет пространство в получающейся программе:
// Types are same, but different order leads to new instantionation of do_something function. types<bool, double, int> types<bool, int, double> types<int, bool, double> types<int, double, bool> types<double, int, bool> types<double, bool, int>
Один из способов уменьшить количество инстанций — заставить типы иметь некоторый порядок:
#include <boost/type_index/ctti_type_index.hpp> // Implementing type trait that returns true if the types are sorted lexographicaly template <class... T> constexpr bool is_asc_sorted(types<T...>) noexcept { return true; } template <class Lhs, class Rhs, class... TN> constexpr bool is_asc_sorted(types<Lhs, Rhs, TN...>) noexcept { using namespace boost::typeindex; return ctti_type_index::type_id<Lhs>() <= ctti_type_index::type_id<Rhs>() && is_asc_sorted(types<Rhs, TN...>()); } // Using the newly created `is_asc_sorted` trait: template <class... T> void do_something(const types<T...>& t) noexcept { static_assert( is_asc_sorted( types<T...>() ), "T... for do_something(const types<T...>& t) must be sorted ascending" ); } int main() { do_something( types<bool, double, int>() ); // do_something( types<bool, int, double>() ); // Fails the static_assert! }
Статья Examples раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 38. Boost.TypeIndex 4.1 может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Chapter 38. Boost.TypeIndex 4.1 ::
реклама |