Skip to content

Instantly share code, notes, and snippets.

@eao197
Created July 24, 2024 04:56
Show Gist options
  • Save eao197/cbd115915408c281bdb0d4d2e85f5456 to your computer and use it in GitHub Desktop.
Save eao197/cbd115915408c281bdb0d4d2e85f5456 to your computer and use it in GitHub Desktop.
A dirty sketch of using root_t<T> and node_t<D, B> to traverse type hierarchy down up
#include <iostream>
#include <typeindex>
#include <stdexcept>
class message_upcaster_t;
using upcaster_factory_t = message_upcaster_t (*)() noexcept;
class message_upcaster_t
{
std::type_index m_self_type;
upcaster_factory_t m_parent_factory;
public:
message_upcaster_t(
std::type_index self_type,
upcaster_factory_t parent_factory )
: m_self_type{ std::move(self_type) }
, m_parent_factory{ parent_factory }
{}
[[nodiscard]] const std::type_index &
self_type() const noexcept
{
return m_self_type;
}
[[nodiscard]] bool
has_parent_factory() const noexcept
{
return nullptr != m_parent_factory;
}
[[nodiscard]] message_upcaster_t
parent_upcaster() const
{
if( !has_parent_factory() )
throw std::runtime_error{
"message_upcaster_t::parent_upcaster: "
"no parent upcaster_factory"
};
return (*m_parent_factory)();
}
};
class message_t
{
public:
virtual ~message_t() = default;
};
class root_base_t : public message_t
{
upcaster_factory_t m_factory{};
public:
[[nodiscard]] upcaster_factory_t
so_message_upcaster_factory() const noexcept
{
return m_factory;
}
void
so_set_message_upcaster_factory(
upcaster_factory_t factory) noexcept
{
m_factory = factory;
}
};
template<typename Base>
class root_t : public root_base_t
{
public:
[[nodiscard]] static message_upcaster_t
so_make_upcaster_root() noexcept
{
return { typeid(Base), nullptr };
}
public:
root_t()
{
this->so_set_message_upcaster_factory( &root_t::so_make_upcaster_root );
}
};
template< typename B, typename = std::void_t<> >
struct has_so_make_upcaster_method : public std::false_type {};
template< typename B >
struct has_so_make_upcaster_method<
B, std::void_t< decltype(&B::so_make_upcaster) >
> : public std::true_type {};
template<typename Derived, typename Base>
class node_t
{
public:
[[nodiscard]] static message_upcaster_t
so_make_upcaster() noexcept
{
if constexpr( has_so_make_upcaster_method<Base>::value )
return { typeid(Derived), &Base::so_make_upcaster };
else
return { typeid(Derived), &Base::so_make_upcaster_root };
}
public:
node_t(Derived & derived)
{
static_assert(
std::is_base_of_v<root_base_t, Derived> &&
std::is_base_of_v<Base, Derived> );
derived.so_set_message_upcaster_factory( &node_t::so_make_upcaster );
}
};
class image_base : public root_t<image_base>
{
public:
image_base() = default;
};
class image_vendor_1
: public image_base
, public node_t<image_vendor_1, image_base>
{
public:
image_vendor_1()
: image_base{}
, node_t<image_vendor_1, image_base>{ *this }
{}
};
class image_vendor_2
: public image_base
, public node_t<image_vendor_2, image_base>
{
public:
image_vendor_2()
: image_base{}
, node_t<image_vendor_2, image_base>{ *this }
{}
};
class special_image
: public image_vendor_2
, public node_t<special_image, image_vendor_2>
{
public:
special_image()
: image_vendor_2{}
, node_t<special_image, image_vendor_2>{ *this }
{}
};
void handle(const image_base & base)
{
auto upcaster = (base.so_message_upcaster_factory())();
std::cout << "self_type: " << upcaster.self_type().name() << std::endl;
while( upcaster.has_parent_factory() )
{
upcaster = upcaster.parent_upcaster();
std::cout << "base_type: " << upcaster.self_type().name() << std::endl;
}
}
int main()
{
special_image img;
handle( img );
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment