Are there alternatives for reflection / introspection in C ++?

18

I have the following problem.

Given any type of T :

template <typename T>
  • I need to be able to convert an object of type T to a std::unordered_map<std::string, boost::any> map containing an entry for each attribute. Initially I think of "flat" objects, with only primitive attributes and strings.

    std::unordered_map<boost::any, boost::any>& asUnordered_map(const T& obj)
    
  • I also need to do the opposite, that is, given a std::map<std::string, boost::any> and a T object I want to update the attributes of the object:

    T& asObject(const std::unordered_map<boost::any, boost::any>& map)
    
  • In Java a natural implementation would use Introspector and techniques reflection .

    It seems however that C ++ still does not support reflection by default (the committee and certain study groups are moving forward on that front for an upcoming release ) and emulating this functionality externally does a good job (see CPP-Reflection ). In this way I would like to know if there is a more idiomatic alternative to solve this type of problem.

    How can I find out what the attributes of an object are and how can I retrieve / modify values of an unknown type in C ++?

        
    asked by anonymous 18.08.2016 / 11:26

    1 answer

    1

    Can you use Boost Hana?

    link

    You will not have reflection, but will work with Meta Real Programming.

    #include <boost/hana.hpp>
    #include <cassert>
    #include <string>
    namespace hana = boost::hana;
    using namespace hana::literals;
    
    struct Fish { std::string name; };
    struct Cat  { std::string name; };
    struct Dog  { std::string name; };
    
    int main() {
      // Sequences capable of holding heterogeneous objects, and algorithms
      // to manipulate them.
      auto animals = hana::make_tuple(Fish{"Nemo"}, Cat{"Garfield"}, Dog{"Snoopy"});
      auto names = hana::transform(animals, [](auto a) {
        return a.name;
      });
      assert(hana::reverse(names) == hana::make_tuple("Snoopy", "Garfield", "Nemo"));
    
      // No compile-time information is lost: even if 'animals' can't be a
      // constant expression because it contains strings, its length is constexpr.
      static_assert(hana::length(animals) == 3u, "");
    
      // Computations on types can be performed with the same syntax as that of
      // normal C++. Believe it or not, everything is done at compile-time.
      auto animal_types = hana::make_tuple(hana::type_c<Fish*>, hana::type_c<Cat&>, hana::type_c<Dog*>);
      auto animal_ptrs = hana::filter(animal_types, [](auto a) {
        return hana::traits::is_pointer(a);
      });
      static_assert(animal_ptrs == hana::make_tuple(hana::type_c<Fish*>, hana::type_c<Dog*>), "");
    
      // And many other goodies to make your life easier, including:
      // 1. Access to elements in a tuple with a sane syntax.
      static_assert(animal_ptrs[0_c] == hana::type_c<Fish*>, "");
      static_assert(animal_ptrs[1_c] == hana::type_c<Dog*>, "");
    
      // 2. Unroll loops at compile-time without hassle.
      std::string s;
      hana::int_c<10>.times([&]{ s += "x"; });
      // equivalent to s += "x"; s += "x"; ... s += "x";
    
      // 3. Easily check whether an expression is valid.
      //    This is usually achieved with complex SFINAE-based tricks.
      auto has_name = hana::is_valid([](auto&& x) -> decltype((void)x.name) { });
      static_assert(has_name(animals[0_c]), "");
      static_assert(!has_name(1), "");
    }
    
        
    02.03.2018 / 13:43