Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to introspect on methods using Boost Hana?

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.

like image 310
seertaak Avatar asked Sep 20 '15 11:09

seertaak


1 Answers

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.

like image 171
Louis Dionne Avatar answered Sep 24 '22 07:09

Louis Dionne