| Home | Libraries | People | FAQ | More

## Examples

### Getting human readable and mangled type names

The following example shows how short (mangled) and human readable type names could be obtained from a type. Works with and without 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
    }

Short names are very compiler dependant: some compiler will output `.H`, others `i`.

Readable names may also differ between compilers: `struct user_defined_type`, `user_defined_type`.

| Warning
With RTTI off different classes with same names in anonymous namespace may collapse. See 'RTTI emulation limitations'.

### Storing information about a type in container

The following example shows how an information about a type could be stored. Example works with and without RTTI.

    #include <boost/type_index.hpp>
    #include <boost/unordered/unordered_set.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>());
    }

### Getting through the inheritance to receive a real type name

The following example shows that `type_info` is able to store the real type, successfully getting through all the inheritances.

Example works with and without RTTI."

    #include <boost/type_index.hpp>
    #include <boost/type_index/runtime_cast/register_runtime_class.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 };
    struct D: public C { BOOST_TYPE_INDEX_REGISTER_RUNTIME_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`

It's also possible to use type_id_runtime with the BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS, which adds additional information for runtime_cast to work.

        D d;
        const A& d_as_a = d;
        print_real_type(d_as_a);    // Outputs `struct D`

    }

### Using runtime_cast where RTTI is unavailable or undesirable

The following example shows that `runtime_cast` is able to find a valid pointer in various class hierarchies regardless of inheritance or type relation.

Example works with and without RTTI."

    #include <boost/type_index/runtime_cast.hpp>
    #include <iostream>

    struct A {
        BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS()
        virtual ~A()
        {}
    };

    struct B {
        BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS()
        virtual ~B()
        {}
    };

    struct C : A {
        BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(A)
    };

    struct D : B {
        BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(B)
    };

    struct E : C, D {
        BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(C, D)
    };

    int main() {
        C c;
        A* a = &c;

        if(C* cp = boost::typeindex::runtime_cast<C*>(a)) {
            std::cout << "Yes, a points to a C: "
                      << a << "->" << cp << '\n';
        }
        else {
            std::cout << "Error: Expected a to point to a C" << '\n';
        }

        if(E* ce = boost::typeindex::runtime_cast<E*>(a)) {
            std::cout << "Error: Expected a to not points to an E: "
                      << a << "->" << ce << '\n';
        }
        else {
            std::cout << "But, a does not point to an E" << '\n';
        }

        E e;
        C* cp2 = &e;
        if(D* dp = boost::typeindex::runtime_cast<D*>(cp2)) {
            std::cout << "Yes, we can cross-cast from a C* to a D* when we actually have an E: "
                      << cp2 << "->" << dp << '\n';
        }
        else {
            std::cout << "Error: Expected cp to point to a D" << '\n';
        }

Alternatively, we can use runtime_pointer_cast so we don't need to specity the target as a pointer. This works for smart_ptr types too.

        A* ap = &e;
        if(B* bp = boost::typeindex::runtime_pointer_cast<B>(ap)) {
            std::cout << "Yes, we can cross-cast and up-cast at the same time."
                      << ap << "->" << bp << '\n';
        }
        else {
            std::cout << "Error: Expected ap to point to a B" << '\n';
        }

        return 0;
    }

### Exact type matching: storing type with const, volatile and reference qualifiers

The following example shows that `type_index` (and `type_info`) is able to store the exact type, without stripping const, volatile and references. Example works with and without RTTI.

In this example we'll create a class that stores a pointer to function and remembers the exact type of the parameter the function accepts. When the call to the bound function is made, he actual input parameter type is checked against the stored parameter type and an exception is thrown in case of mismatch.

    #include <boost/type_index.hpp>
    #include <iostream>
    #include <stdexcept>
    #include <cstdlib>

    #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*/) {}
    }

### Table of raw_name() and pretty_name() outputs with and without RTTI

The following example shows how different type names look when we explicitly use classes for RTTI and RTT off.

This example requires RTTI. For a more portable example see 'Getting human readable and mangled type names':

    #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";
    }

Code from the example will produce the following table:

Table 39.2. Table of names

Type | RTTI & raw_name | RTTI & pretty_name | noRTTI & raw_name
--- | --- | --- | ---
User defined type | `17user_defined_type` | `user_defined_type` | `user_defined_type]`
In anonymous namespace | `N12_GLOBAL__N_112in_anon_typeE` | `(anonymous namespace)::in_anon_type` | `{anonymous}::in_anon_type]`
In ns3::{anonymous}::ns4 namespace | `N3ns312_GLOBAL__N_13ns412in_anon_typeE` | `ns3::(anonymous namespace)::ns4::in_anon_type` | `ns3::{anonymous}::ns4::in_anon_type]`
Template class | `5templIsiE` | `templ<short, int>` | `templ<short int, int>]`
Template class (full specialization) | `5templIiiE` | `templ<int, int>` | `templ<int, int>]`
Template class with template classes | `5templIS_IcaES_Ii17user_defined_typeEE` | `templ<templ<char, signed char>, templ<int, user_defined_type> >` | `templ<templ<char, signed char>, templ<int, user_defined_type> >]`

We have not show the "noRTTI & pretty_name" column in the table because it is almost equal to "noRTTI & raw_name" column.

| Warning
With RTTI off different classes with same names in anonymous namespace may collapse. See 'RTTI emulation limitations'.

### C++14: Checking namespace at compile time

The following example shows that `boost::typeindex::ctti_type_index` is usable at compile time on a C++14 compatible compilers.

In this example we'll create and use a constexpr function that checks namespace of the provided type.

    #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, "::");
    }

Now when we have that wonderfull function, we can do static assertions and other compile-time validations:

    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
                // ...
                do_something(value);
            }
        };

        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!
    }

### C++14: Checking lexigraphical order of provided types

The following example shows that `boost::typeindex::ctti_type_index` is usable at compile time on a C++14 compatible compilers to check order of template parameters.

Consider the situation when we have a function that accepts std::tuple, boost::variant or some other class that uses variadic templates:

    template <class... T> class types{};

    template <class... T>
    void do_something(const types<T...>& t) noexcept;

Such functions may be very usefull, however they may significantly increase the size of the resulting program. Each instantionation of such function with different templates order consumes space in the resulting program:

    // 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>

One of the ways to reduce instantinations count is to force the types to have some order:

    #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...>& /*value*/) 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!
    }