Generally you shouldn't need to do this, but here is a guide for implementing your own Sequence
as well as fulfilling requirements for other concepts in Boost.Hana. (The latter of which should be useful to end users who are not providing their own implementation of a tuple.)
Start with the Minimal Complete Definition (MCD) in the documentation for hana::Sequence
There you will see that to implement a Sequence
your data type must implement the make
function as well as satisfy the requirements for Iterable
and Foldable
.
So the full list of Hana functions you must provide implementations for are as follows:
at
drop_front
is_empty
make
unpack
Additionally, note that Boost.Hana has two tuple types tuple
and basic_tuple
. basic_tuple
is more light weight so you should use that for your storage.
To use Boost.Hana's tag dispatching you can implement hana::tag_of
or simply provide a hana_tag
type alias as a member of your class.
#include <boost/hana.hpp>
#include <utility>
namespace mine {
struct my_custom_tuple_tag { };
template<typename ... args>
struct my_custom_tuple_t {
using hana_tag = my_custom_tuple_tag;
//... all other stuff
boost::hana::basic_tuple<args ...> tup;
auto my_getter() const {
return boost::hana::at_c<1>(tup);
}
};
}
namespace boost::hana {
// Iterable
template <>
struct at_impl<mine::my_custom_tuple_tag> {
template <typename Xs, typename N>
static constexpr decltype(auto) apply(Xs&& xs, N const&) {
return at_impl<basic_tuple_tag>(std::forward<Xs>(xs).tup, N{});
}
};
template <>
struct drop_front_impl<mine::my_custom_tuple_tag> {
template <typename Xs, typename N>
static constexpr auto apply(Xs&& xs, N const&) {
return drop_front_impl<basic_tuple_tag>(std::forward<Xs>(xs).tup);
}
};
template <>
struct is_empty_impl<mine::my_custom_tuple_tag> {
template <typename Xs>
static constexpr auto apply(Xs const& xs) {
return is_empty_impl<basic_tuple_tag>(xs).tup;
}
};
// Foldable
template <>
struct unpack_impl<mine::my_custom_tuple_tag> {
template <typename Xs, typename F>
static constexpr auto apply(Xs&& xs, F&& f) {
return unpack_impl<basic_tuple_tag>(std::forward<Xs>(xs).tup,
std::forward<F>(f));
}
};
// Sequence
template <>
struct make_impl<mine::my_custom_tuple_tag> {
template <typename ...Args>
static constexpr auto apply(Args&& ...args) {
return make_impl<basic_tuple_tag>(std::forward<Args>(args)...);
}
};
template <>
struct Sequence<mine::my_custom_tuple_tag> : std::true_type { };
}
It is worth noting that the template for checking Sequence
is simply an opt-in template specialization. I'm sure this is just a short cut to save on compile-time computations as the other concepts rely on checking for non-default implementations of their required functions.
https://godbolt.org/z/iaYBFq