Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Examples

Boost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 38. Boost.TypeIndex 4.1

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Следующий пример показывает, как короткие (смешанные) и понятные для человека названия типов могут быть получены из типа. Работает с RTTI и без него.

#include <boost/type_index.hpp>
#include <iostream>
template <class T>
void foo(T) {
    std::cout << "\n Short name: " << boost::typeindex::type_id<T>().raw_name();
    std::cout << "\n Readable name: " << boost::typeindex::type_id<T>().pretty_name();
}
struct user_defined_type{};
namespace ns1 { namespace ns2 {
    struct user_defined_type{};
}} // namespace ns1::ns2
namespace {
    struct in_anon_type{};
} // anonymous namespace
int main() {
    // Call to
    foo(1);
    // will output something like this:
    //
    // (RTTI on)                                            (RTTI off)
    // Short name: i                                        Short name: int]
    // Readable name: int                                   Readable name: int
    user_defined_type t;
    foo(t);
    // Will output:
    //
    // (RTTI on)                                            (RTTI off)
    // Short name: 17user_defined_type                      user_defined_type]
    // Readable name: user_defined_type                     user_defined_type
    ns1::ns2::user_defined_type t_in_ns;
    foo(t_in_ns);
    // Will output:
    //
    // (RTTI on)                                            (RTTI off)
    // Short name: N3ns13ns217user_defined_typeE            ns1::ns2::user_defined_type]
    // Readable name: ns1::ns2::user_defined_type           ns1::ns2::user_defined_type
    in_anon_type anon_t;
    foo(anon_t);
    // Will output:
    //
    // (RTTI on)                                            (RTTI off)
    // Short name: N12_GLOBAL__N_112in_anon_typeE           {anonymous}::in_anon_type]
    // Readable name: (anonymous namespace)::in_anon_type   {anonymous}::in_anon_type
}

Короткие имена очень зависят от компилятора: один компилятор выведет<.H>, другие<i>.

Читаемые имена могут также различаться между компиляторами:<struct user_defined_type>,<user_defined_type>.

[Warning] 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

Тип пользователя

<17user_defined_type>

<user_defined_type>

<user_defined_type]>

В анонимном пространстве имен

<N12_GLOBAL__N_112in_anon_typeE>

<(anonymous namespace)::in_anon_type>

<{anonymous}::in_anon_type]>

В ns3::{anonymous}::ns4 namespace

<N3ns312_GLOBAL__N_13ns412in_anon_typeE>

<ns3::(anonymousnamespace)::ns4::in_anon_type>

<ns3::{anonymous}::ns4::in_anon_type]>

Класс шаблонов

<5templIsiE>

<templ<short, int>>

<templ<shortint,int>]>

Класс шаблонов (полная специализация)

<5templIiiE>

<templ<int,int>>

<templ<int,int>]>

Класс шаблонов с классами шаблонов

<5templIS_IcaES_Ii17user_defined_typeEE>

<templ<templ<char, signedchar>,templ<int,user_defined_type>>>

<templ<templ<char, signedchar>,templ<int,user_defined_type>>]>


Мы не показываем колонку «noRTTI & pretty_name» в таблице, потому что она почти равна колонке «noRTTI & raw_name».

[Warning] 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!
}

PrevUpHomeNext

Статья Examples раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 38. Boost.TypeIndex 4.1 может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 38. Boost.TypeIndex 4.1 ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 17:34:51/0.031209945678711/1