diff --git a/doc/describe/changes.adoc b/doc/describe/changes.adoc index ec32e2b..07b4dac 100644 --- a/doc/describe/changes.adoc +++ b/doc/describe/changes.adoc @@ -8,6 +8,10 @@ https://www.boost.org/LICENSE_1_0.txt # Revision History :idprefix: +## Changes in Boost 1.80.0 + +* Added example of defining a `Boost Hana` class adapter. + ## Changes in Boost 1.79.0 * Enabled unions in `BOOST_DESCRIBE_STRUCT` and updated examples to check `std::is_union`. diff --git a/doc/describe/examples.adoc b/doc/describe/examples.adoc index 8385d60..6eaf423 100644 --- a/doc/describe/examples.adoc +++ b/doc/describe/examples.adoc @@ -492,3 +492,14 @@ Sample output: &Y::g [int() const] &Z::(unknown) [void()] ---- + +[#example_boost_hana_struct_adapter] +## `Boost Hana` Struct Adapter + +This example defines a https://github.com/boostorg/hana[`Boost Hana`] adapter +for described structs. + +[source] +---- +include::../../example/hana.cpp[lines=5..-1] +---- diff --git a/example/hana.cpp b/example/hana.cpp new file mode 100644 index 0000000..303b793 --- /dev/null +++ b/example/hana.cpp @@ -0,0 +1,117 @@ +// Copyright 2022 Denis Mikhailov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +// g++ -std=c++17 -Iinclude example/hana.cpp -o example/hana + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { namespace hana { + namespace adapt_describe_detail { + template + struct member_ptr { + template + constexpr decltype(auto) operator()(T&& t) const + { return static_cast(t).*ptr; } + }; + + constexpr std::size_t strlen(char const* s) { + std::size_t n = 0; + while (*s++ != '\0') + ++n; + return n; + } + + template + constexpr auto prepare_member_name_impl(std::index_sequence) { + return hana::string_c< D::name[i]... >; + } + + template + constexpr auto prepare_member_name() { + constexpr std::size_t len = strlen(D::name); + return prepare_member_name_impl(std::make_index_sequence{}); + } + + template class L, class... D> + constexpr auto hana_accessors_apply_impl(L) + { + return ::boost::hana::make_tuple( + ::boost::hana::make_pair( + prepare_member_name(), + member_ptr{} + ) ... + ); + } + } + template + struct accessors_impl::value && + boost::describe::has_describe_members::value && + !std::is_union::value> > + { + static BOOST_HANA_CONSTEXPR_LAMBDA auto apply() + { + using Dm = boost::describe::describe_members; + return adapt_describe_detail::hana_accessors_apply_impl(Dm()); + } + }; +}} + + + + +namespace hana = boost::hana; +struct PersonName { + std::string name; +}; +BOOST_DESCRIBE_STRUCT(PersonName, (), (name)) + +struct PersonAge { + int age; +}; +BOOST_DESCRIBE_STRUCT(PersonAge, (), (age)) + +struct Person : PersonName, PersonAge { +}; +BOOST_DESCRIBE_STRUCT(Person, (PersonName, PersonAge), ()) + + +// The member names are hana::strings: +auto names = hana::transform(hana::accessors(), hana::first); +BOOST_HANA_CONSTANT_CHECK( + names == hana::make_tuple(BOOST_HANA_STRING("name"), BOOST_HANA_STRING("age")) +); + +int main() { + Person john{"John", 30}, bob{"Bob", 40}; + BOOST_HANA_RUNTIME_CHECK(hana::equal(john, john)); + BOOST_HANA_RUNTIME_CHECK(hana::not_equal(john, bob)); + BOOST_HANA_RUNTIME_CHECK(hana::find(john, BOOST_HANA_STRING("name")) == hana::just("John")); + BOOST_HANA_RUNTIME_CHECK(hana::find(john, BOOST_HANA_STRING("age")) == hana::just(30)); + BOOST_HANA_CONSTANT_CHECK(hana::find(john, BOOST_HANA_STRING("foo")) == hana::nothing); + BOOST_HANA_RUNTIME_CHECK(hana::to_tuple(john) == hana::make_tuple( + hana::make_pair(BOOST_HANA_STRING("name"), "John"), + hana::make_pair(BOOST_HANA_STRING("age"), 30) + )); + BOOST_HANA_RUNTIME_CHECK(hana::to_map(john) == hana::make_map( + hana::make_pair(BOOST_HANA_STRING("name"), "John"), + hana::make_pair(BOOST_HANA_STRING("age"), 30) + )); +}