Is it possible to introspect on methods using Boost Hana?
Asked Answered
H

1

8

Boost Hana provides the ability to introspect on class member fields in a simple and beautiful way:

// define:

struct Person {
  std::string name;
  int age;
};

// below could be done inline, but I prefer not polluting the 
// declaration of the struct
BOOST_HANA_ADAPT_STRUCT(not_my_namespace::Person, name, age);

// then:

Person john{"John", 30};
hana::for_each(john, [](auto pair) {
  std::cout << hana::to<char const*>(hana::first(pair)) << ": "
            << hana::second(pair) << std::endl;
});

However, the documentation only mentions member fields. I would like to introspect on methods also. I've tried to naively extend the example with a method:

struct Foo {
    std::string get_name() const { return "louis"; }
};

BOOST_HANA_ADAPT_STRUCT(::Foo, get_name);

This compiles. However, as soon as I try to use it, using code similar to the above (for_each...), I get many compile errors. Since there are no examples that show introspection of methods, I'm wondering whether it is supported.

Haslett answered 20/9, 2015 at 11:6 Comment(1)
It is supported, but I agree that it could be documented better. You can look at the Minimal complete definition section of the Struct concept. I don't have time to compose a full answer right now, but I'll try to do it in the next days (and also update the tutorial).Hooper
H
9

My original answer was crap; sorry for that. Here's a rewrite that actually answers the question.

I just added a macro to allow easily defining a Struct with custom accessors. Here's how you could do it:

#include <boost/hana/adapt_adt.hpp>
#include <boost/hana/at_key.hpp>
#include <boost/hana/string.hpp>
#include <cassert>
#include <string>
namespace hana = boost::hana;

struct Person {
    Person(std::string const& name, int age) : name_(name), age_(age) { }
    std::string const& get_name() const { return name_; }
    int get_age() const { return age_; }
private:
    std::string name_;
    int age_;
};

BOOST_HANA_ADAPT_ADT(Person,
    (name, [](auto const& p) { return p.get_name(); }),
    (age, [](auto const& p) { return p.get_age(); })
);

int main() {
    Person bob{"Bob", 30};
    assert(hana::at_key(bob, BOOST_HANA_STRING("name")) == "Bob");
    assert(hana::at_key(bob, BOOST_HANA_STRING("age")) == 30);
}

That code should work on master. Otherwise, if you need more control over the definition of your accessors or the keys used to map to them, you can also define the whole thing by hand:

namespace boost { namespace hana {
    template <>
    struct accessors_impl<Person> {
        static auto apply() {
            return hana::make_tuple(
                hana::make_pair(BOOST_HANA_STRING("name"), [](auto&& p) -> std::string const& {
                    return p.get_name();
                }),
                hana::make_pair(BOOST_HANA_STRING("age"), [](auto&& p) {
                    return p.get_age();
                })
            );
        }
    };
}}

You can find more information about how to define Structs in the reference for the Struct concept.

Hooper answered 22/9, 2015 at 6:57 Comment(2)
@Haslett Does that answer your question? If so, could you please accept it and otherwise, please let me know what's missing so I can help you and perhaps improve the usability of the library.Hooper
Yes, it does! Apologies for the late reply.Haslett

© 2022 - 2024 — McMap. All rights reserved.