Info
-
Did you know that you can simplify
boost.mp11
API with DSL?**- https://github.com/boostorg/mp11
- DSL - Domain Specific Language
Example
template <class T1, class T2>
[[nodiscard]] constexpr auto operator==(const T1&, const T2&) { return std::is_same_v<T1, T2>; }
template <class... Ts>
constexpr auto list = mp11::mp_list<Ts...>{};
static_assert(list<> == list<>);
static_assert(list<int> == list<int>);
static_assert(list<int, double> == list<int, double>);
Puzzle
- Can you implement DSL for boost.mp11
struct event {};
class foo1 : event {};
class foo2 : event { int i; };
class bar1 {};
class bar2 { int i; };
template<class... Ts>
constexpr auto unique_event_ptrs =
list<Ts...>
| unique
| filter<is_base_of<event>>
| transform<add_pointer>
;
static_assert(unique_event_ptrs<> == list<>);
static_assert(unique_event_ptrs<foo1> == list<foo1*>);
static_assert(unique_event_ptrs<foo1, foo1> == list<foo1*>);
static_assert(unique_event_ptrs<bar1> == list<>);
static_assert(unique_event_ptrs<bar1, bar1> == list<>);
static_assert(unique_event_ptrs<bar2, bar1> == list<>);
static_assert(unique_event_ptrs<foo2, foo1> == list<foo2*, foo1*>);
static_assert(unique_event_ptrs<foo1, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, foo2, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, foo1, foo2, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, foo2, foo1, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, bar1, foo1, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, bar1, foo1, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, bar1, foo1, foo1, bar1, bar2> == list<foo1*>);
Solutions
template <class... Ts>
constexpr auto list = mp11::mp_list<Ts...>{};
struct unique {
} unique;
template <template <typename...> class List, typename... Ts>
constexpr auto operator|(const List<Ts...> &, struct unique)
-> mp11::mp_unique<List<Ts...>> {
return {};
};
template <typename F>
struct filter_t {};
template <typename F>
constexpr auto filter = filter_t<F>{};
template <class B>
struct is_base_of {
template <class D>
using fn = std::is_base_of<B, D>;
};
template <typename F, template <typename...> class List, typename... Ts>
constexpr auto operator|(const List<Ts...> &, const filter_t<F> &)
-> mp11::mp_filter_q<F, List<Ts...>> {
return {};
};
template <typename F>
struct transform_t {};
template <typename F>
constexpr auto transform = transform_t<F>{};
struct add_pointer {
template <class T>
using fn = T *;
};
template <typename F, template <typename...> class List, typename... Ts>
constexpr auto operator|(const List<Ts...> &, const transform_t<F> &)
-> mp11::mp_transform_q<F, List<Ts...>> {
return {};
};
template <class T1, class T2>
constexpr auto operator==(const T1 &, const T2 &) {
return std::is_same_v<T1, T2>;
}
#include <boost/mp11.hpp>
using namespace boost::mp11;
template<class T1, class T2>
[[nodiscard]] constexpr auto operator==(const T1 &, const T2 &) { return std::is_same_v<T1, T2>; }
template<class T, class Q>
[[nodiscard]] constexpr auto operator|(const T &, const Q &) { return mp_invoke_q<Q, T>{}; }
template<class... Ts>
constexpr auto list = mp_list<Ts...>{};
constexpr mp_quote<mp_unique> unique;
template <class T>
using is_base_of = mp_bind_front<std::is_base_of, T>;
using add_pointer = mp_quote_trait<std::add_pointer>;
template<class Q>
constexpr mp_bind_front<mp_filter_q, Q> filter;
template<class Q>
constexpr mp_bind_front<mp_transform_q, Q> transform;
struct event {
};
class foo1 : event {
};
class foo2 : event {
int i;
};
class bar1 {
};
class bar2 {
int i;
};
template<class... Ts>
constexpr auto unique_event_ptrs =
list<Ts...> | unique | filter<is_base_of<event>> | transform<add_pointer>;
static_assert(unique_event_ptrs<> == list<>);
static_assert(unique_event_ptrs<foo1> == list<foo1*>);
static_assert(unique_event_ptrs<foo1, foo1> == list<foo1*>);
static_assert(unique_event_ptrs<bar1> == list<>);
static_assert(unique_event_ptrs<bar1, bar1> == list<>);
static_assert(unique_event_ptrs<bar2, bar1> == list<>);
static_assert(unique_event_ptrs<foo2, foo1> == list<foo2*, foo1*>);
static_assert(unique_event_ptrs<foo1, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, foo2, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, foo1, foo2, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, foo2, foo1, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, bar1, foo1, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, bar1, foo1, foo2> == list<foo1*, foo2*>);
static_assert(unique_event_ptrs<foo1, bar1, foo1, foo1, bar1, bar2> ==
list<foo1*>);