Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate over boost::fusion associative struct and access in a generic way the keys

This is my very first question into this great knowledge exchange and I hope I find some help.

I try to implement a generic way to create PrintTo functions (later to be used in GoogleTest).

So the following code does just half of the job. It only prints the values of the defined struct Foo::Bar

#include <iostream>
#include <sstream>
#include <string>

#include <boost/fusion/container.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/adapted/struct/define_assoc_struct.hpp>
#include <boost/fusion/include/define_assoc_struct.hpp>

namespace Foo
{
  namespace Keys
  {
    struct StringField;
    struct IntField;
  };
}

BOOST_FUSION_DEFINE_ASSOC_STRUCT(
  (Foo), Bar,
  (std::string, stringField, Foo::Keys::StringField)
  (int,         intField,    Foo::Keys::IntField))


struct fusion_printer_impl
{
  std::ostream& _os;

  fusion_printer_impl(std::ostream& os) 
    : _os(os) {}

  template <typename T>
  void operator() (T& v) const
  {
    _os << v << std::endl;
  }
};

void PrintTo(Foo::Bar const& v, std::ostream* os)
{
  boost::fusion::for_each(v, fusion_printer_impl(*os));
}

int main()
{
  Foo::Bar fb("Don't panic!", 42);
  std::ostringstream temp;

  PrintTo(fb, &temp);

  std::cout << temp.str() << std::endl;
}

So what I am looking for is a way to print automatically the Foo::Keys as well. I looked into the makro generated code of BOOST_FUSION_DEFINE_ASSOC_STRUCT and as far as I can see the Keys are available as static const char* boost::fusion::extension::struct_member_name::call().

I looked into the code of fusion::for_each and I so far I see only a way to 'replicate' the complete code so that fusion_printer_impl::operator() is been called with two parameters, Key and values. Before I go into that direction I would like to know if there is an easier ways to accomplish this.

I know that it is possible to define explicit a boost::fusion::map. Here one gets automatically access through the fusion::pair to Key type and value. But this is currently no option for me.

So any help here is welcome.

like image 308
Felix Petriconi Avatar asked Apr 30 '13 13:04

Felix Petriconi


1 Answers

Yours is a good question, hopefully somebody here will come to something cleaner than this:

...
struct fusion_printer_2
{
    typedef std::ostream* result_type;

    // Well, not really the intented use but...
    template<typename T>
    std::ostream* operator()(std::ostream const* out, const T& t) const
    {
        std::ostream* const_violated_out = const_cast<result_type>(out);
        (*const_violated_out) << 
            (std::string( typeid( typename boost::fusion::result_of::key_of<T>::type ).name() ) + ": " + boost::lexical_cast<std::string>(deref(t))) << std::endl;
        return const_violated_out;
    }
};

void PrintTo(Foo::Bar const& v, std::ostream* os)
{
  boost::fusion::iter_fold(v, os, fusion_printer_2());
}
...
like image 111
dsign Avatar answered Oct 06 '22 18:10

dsign