#pragma once namespace stx { template class type_counter; // Type information for given Info type, also serving as tag template class type_info final : public Info { // Current type id (starts from 0) unsigned type = 0u - 1; // Next typeinfo in linked list type_info* next = nullptr; type_info(Info info, decltype(sizeof(int))) noexcept; friend type_counter; public: constexpr type_info() noexcept : Info() { } unsigned index() const { return type; } }; // Class for automatic type registration for given Info type template class type_counter final { // Dummy first element to simplify list filling logic type_info first{}; // Linked list built at global initialization time type_info* next = &first; friend type_info; public: constexpr type_counter() noexcept = default; unsigned count() const { return next->index() + 1; } class const_iterator { const type_info* ptr; public: const_iterator(const type_info* ptr) : ptr(ptr) { } const type_info& operator*() const { return *ptr; } const type_info* operator->() const { return ptr; } const_iterator& operator++() { ptr = ptr->next; return *this; } const_iterator operator++(int) { const_iterator r = ptr; ptr = ptr->next; return r; } bool operator==(const const_iterator& r) const { return ptr == r.ptr; } bool operator!=(const const_iterator& r) const { return ptr != r.ptr; } }; const_iterator begin() const { return first.next; } const_iterator end() const { return nullptr; } // Global type info instance template static inline const type_info type{Info::template make_typeinfo(), sizeof(T)}; }; // Global typecounter instance template auto& typelist() { static type_counter typelist_v; return typelist_v; } template type_info::type_info(Info info, decltype(sizeof(int))) noexcept : Info(info) , type(typelist().count()) { // Update linked list auto& tl = typelist(); tl.next->next = this; tl.next = this; } // Type index accessor template inline unsigned typeindex() noexcept { return type_counter::template type.index(); } // Type info accessor template inline const Info& typedata() noexcept { return type_counter::template type; } }