Info
-
Did you know about C++17 variadic using declaration?
Example
template<class... TEvents>
struct ihandler : ihandler<TEvents>... {
virtual ~ihandler() noexcept = default;
using ihandler<TEvents>::on...;
};
template<class TEvent> struct ihandler<TEvent> {
virtual ~ihandler() noexcept = default;
virtual auto on(const TEvent&) -> bool = 0;
};
int main() {
struct foo {};
struct bar {};
struct handler : ihandler<foo, bar> {
auto on(const foo&) -> bool override { return true; }
auto on(const bar&) -> bool override { return false; }
};
std::unique_ptr<ihandler<foo, bar>> h = std::make_unique<handler>();
assert(h->on(foo{}));
assert(not h->on(bar{}));
}
Puzzle
- Can you implement
handler
which will implement an interfaceT
for givenTs...
and returnsTs::value
?
template<class... TEvents>
struct ihandler : ihandler<TEvents>... {
virtual ~ihandler() noexcept = default;
using ihandler<TEvents>::on...;
};
template<class TEvent> struct ihandler<TEvent> {
virtual ~ihandler() noexcept = default;
virtual auto on(const TEvent&) -> bool = 0;
};
template<template<class...> class T, class... Ts>
struct handler final; // TODO
int main() {
using namespace boost::ut;
"handler"_test = [] {
struct foo { bool value{}; };
struct bar { bool value{}; };
auto h = std::make_unique<handler<ihandler, foo, bar>>();
expect(h->on(foo{.value = true}) and
static_cast<ihandler<foo>*>(h.get())->on(foo{.value = true})
);
expect(not h->on(bar{.value = false}) and
not static_cast<ihandler<bar>*>(h.get())->on(bar{.value = false})
);
};
}
Solutions
template<class T, template<class...> class U>
struct handler_helper:U<T>
{
auto on(const T& t) -> bool override{
return t.value;
}
};
template<template<class...> class T, class... Ts>
struct handler final : handler_helper<Ts,T> ...
{
using handler_helper<Ts,T>::on...;
};
namespace detail {
template<template<class...> class I, class T>
struct handler : I<T> {
auto on(const T& t) -> bool override {
return t.value;
}
};
} // namespace detail
template<template<class...> class T, class... Ts>
struct handler final : detail::handler<T, Ts>... {
using detail::handler<T, Ts>::on...;
};
namespace detail {
template <template<class> class Interface, class TEvent>
struct handler_impl : Interface<TEvent> {
auto on(const TEvent& event) -> bool override { return event.value; }
};
}
template <template<class> class Interface, class... TEvents>
struct handler final : detail::handler_impl<Interface, TEvents>... {
using detail::handler_impl<Interface, TEvents>::on...;
};
template<template<class...> class T, class... Ts>
struct handler final : handler<T, Ts>... {
using handler<T, Ts>::on...;
};
template<template<class...> class T, class TEvent>
struct handler<T, TEvent> : T<TEvent> {
auto on(const TEvent& event) -> bool final {
return event.value;
}
};
namespace detail {
template <template <class...> class TContainer, class T>
struct handler_impl : TContainer<T> {
[[nodiscard]] constexpr auto on(const T& t) -> bool override {
return t.value;
}
};
} // namespace detail
template <template <class...> class T, class... Ts>
struct handler final : detail::handler_impl<T, Ts>... {
using detail::handler_impl<T, Ts>::on...;
};
template<class T>
struct on_method : ihandler<T> {
bool on(T const& t) { return t.value; }
};
template<template<class...> class T, class... Ts>
struct handler final : on_method<Ts>... {
using on_method<Ts>::on...;
};