Boost Fusion and Fusion.Adapt.Struct Example

The fusion example cpp files below build with boost 1.47.0 g++ 4.6.3 (and boost 1.35.0, g++ 4..4.6). Refer to my earlier C++ reflection post for further details. (A example of boost struct serializer, and the more generic example behind it).

  • The 1st example is just a simple fusion hello-world test.
  • The 2nd example shows the introspection of a C struct by adapt.struct.
  • The 3rd shows recursive descending iteration into struct member in a struct, by not-a-pure C++ or boost approach.
  • The 4th example fixes the types in the 3rd example. It is a pure C++ approach.
  • The 5th example, using boost::mpl::eval_if thus avoiding one stub function for each primitive type.
  • Finally it comes the 6th example, complete with array handling, struct field name, type, value, with lot of code.
           

/*                                                                                                 
 * compile with g++ 4.6.3: g++ -I ./boost_1_47_0/ test1.cpp
 */

#include <typeinfo>
#include <string>
#include <iostream>

#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/vector.hpp>

using namespace boost::fusion;

struct print_vars {
    template <typename T>
    void operator()(T const & x) const {
        std::cout << '<' << typeid(x).name() <<  ' ' << x << '>';
    };
};

int main(int argc, char *argv[]) 
{
  vector<int,char,std::string> stuff(1,'x',"howdy");
  int i = at_c<0>(stuff);
  char ch = at_c<1>(stuff);
  std::string s = at_c<2>(stuff);

  for_each(stuff, print_vars());

  return 0;
}

And the 2nd example below shows the use of fusion.adapt.struct.

/* 
 * compile with g++ 4.6.3: g++ -I ./boost_1_47_0/ test2.cpp
 */

#include <typeinfo>
#include <string>
#include <iostream>

#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/vector.hpp>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/lexical_cast.hpp>

#include <stdio.h>

using namespace boost::fusion;

struct print_vars {
    template <typename T>
    void operator()(T const & x) const {
        std::cout << '<' << typeid(x).name() <<  ' ' << x << '>';
    };
};

// Your existing struct
struct Foo
{
    int i;
    bool j;
    char k[100];
};

// Generate an adapter allowing to view "Foo" as a Boost.Fusion sequence
BOOST_FUSION_ADAPT_STRUCT(
    Foo,
    (int, i)
    (bool, j)
    (char, k[100])
)

// The action we will call on each member of Foo
struct AppendToTextBox
{
    //AppendToTextBox(RichEditControl& Ctrl) : m_Ctrl(Ctrl){}
    template <typename T>
    void operator()(T& t) const {
        printf("  --%s--%s--  \n", 
               typeid(t).name(), 
               boost::lexical_cast<std::string>(t).c_str());
        if (typeid(t).name()[0] == 'c')
            printf("  --%s--%s--  \n", 
                   typeid(t).name(), t);
    }
    //RichEditControl& m_Ctrl;
};

// Usage:
//void FillTextBox(Foo& F, RichEditControl& Ctrl)
//{
//    boost::fusion::for_each(F, AppendToTextBox(Ctrl));
//}

int main(int argc, char *argv[]) 
{
  vector<int,char,std::string> stuff(1,'x',"howdy");
  int i = at_c<0>(stuff);
  char ch = at_c<1>(stuff);
  std::string s = at_c<2>(stuff);

  for_each(stuff, print_vars());

  struct Foo f = { 33, false, "abcd" };
  for_each(f, AppendToTextBox());

  return 0;
}

The 3rd example of recursive descending iteration into a struct member in a struct:

/*
 * compile with g++ 4.4.6: g++ -I boost_1_35_0 test3.cpp
 */
#include <typeinfo>
#include <string>

#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/size.hpp>
#include <boost/lexical_cast.hpp>
#include <cxxabi.h>

#include <stdio.h>
using namespace boost::fusion;

struct Foo_s { int i; };
BOOST_FUSION_ADAPT_STRUCT( Foo_s,  (int, i) )

struct Bar_s { int v; Foo_s w; };
BOOST_FUSION_ADAPT_STRUCT( Bar_s, (int, v)  (Foo_s, w) )

struct AppendToTextBox {
    template <typename T>
    void operator()(T& t) const {
        int status = 0;
        const char *realname = abi::__cxa_demangle(typeid(t).name(), 0, 0, &status);
        printf("  typename: %s  value: %s  realname: %s\n", typeid(t).name(),
               boost::lexical_cast(t).c_str(), realname);

        std::string rn(realname);
        if ( rn.rfind("_s") == rn.size()-2 ) {
#if 0 /* this can not compile */
            for_each(t, AppendToTextBox());
#else
            decode(&t, rn);
#endif
        }
    }
};

void decode(void *f, std::string & intype ) {
    if ( intype.find("Foo_s") == 0 ) 
        for_each( *(Foo_s *)f, AppendToTextBox());
};

int main(int argc, char *argv[]) {
  Bar_s f = { 2, { 3 } };
  for_each(f, AppendToTextBox());
  return 0;
}

The 4th example, a working all-typed recursive descendant struct walker.

/*
 * compile with g++ 4.4.6: g++ -I boost_1_35_0 test4.cpp
 */
#include <typeinfo>
#include <string>

#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/lexical_cast.hpp>
#include <cxxabi.h>
#include <stdio.h>
using namespace boost::fusion;

struct Foo_s { int i; char k[100]; };
BOOST_FUSION_ADAPT_STRUCT( Foo_s,  (int, i)  (char, k[100]) )

struct Bar_s { int v; Foo_s w; };
BOOST_FUSION_ADAPT_STRUCT( Bar_s, (int, v)  (Foo_s, w) )

template <typename T2> struct Dec_s {  static void decode(T2   & f); };

struct AppendToTextBox {
    template <typename T>
    void operator()(T& t) const {
        int status = 0;
        const char *realname = abi::__cxa_demangle(typeid(t).name(), 0, 0, &status);
        printf("  typename: %s  value: %s  realname: %s\n", typeid(t).name(),
               boost::lexical_cast<std::string>(t).c_str(), realname);

        Dec_s<T>::decode(t);
    }
};

template <typename T2> void Dec_s<T2>::decode(T2 & f) {
    for_each(f, AppendToTextBox());
};
template <> void Dec_s<int >::decode(int  & f) {};
template <> void Dec_s<char>::decode(char & f) {};

int main(int argc, char *argv[]) {
  Bar_s f = { 2, { 3, "abcd" } };
  Dec_s<Bar_s>::decode(f);
  return 0;
}

Another example using boost::mpl::eval_if thus avoiding multiple stubs for each primitive type.

/* compile with g++ 4.4.6: g++ -I boost_1_35_0 test5.cpp */
#include <typeinfo>
#include <string>
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/lexical_cast.hpp>
#include <cxxabi.h>
#include <stdio.h>
using namespace boost::fusion;

struct Foo_s { int i; char k[100]; };
BOOST_FUSION_ADAPT_STRUCT( Foo_s,  (int, i)  (char, k[100]) )

struct Bar_s { int v; Foo_s w; };
BOOST_FUSION_ADAPT_STRUCT( Bar_s, (int, v)  (Foo_s, w) )

template <typename T2> struct Dec_s;
struct AppendToTextBox {
  template <typename T> void operator()(T& t) const {
        int status = 0;
        const char *realname = abi::__cxa_demangle(typeid(t).name(), 0, 0, &status);
        printf("  typename: %s  value: %s  realname: %s\n", typeid(t).name(),
               boost::lexical_cast(t).c_str(), realname);

        Dec_s<T>::decode(t);
  }
};

template <typename T2> struct DecImplSeq_s {
  typedef DecImplSeq_s<T2> type;
  static void decode(T2   & f) { for_each(f, AppendToTextBox()); };
};

template <typename T2> struct DecImplVoid_s {
  typedef DecImplVoid_s<T2> type;
  static void decode(T2   & f) { };
};

template <typename T2> struct DecCalc_s {
  typedef typename
    boost::mpl::eval_if< traits::is_sequence<T2>, DecImplSeq_s<T2>, DecImplVoid_s<T2> >
  ::type type;
};

template <typename T2> struct Dec_s : public DecCalc_s<T2>::type { };

int main(int argc, char *argv[]) {
  Bar_s f = { 2, { 3, "abcd" } };
  Dec_s<Bar_s>::decode(f);
  return 0;
}

Now the 6th example, complete with field name, type, value, and array.

/* compile with g++ 4.4.6: g++ -I boost_1_35_0 test6.cpp (g++ 4.5.1 boost 1.47.0) */
#include <typeinfo>
#include <string>
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/type_traits.hpp> // is_array, is_class, remove_bounds
#include <boost/lexical_cast.hpp>
#include <cxxabi.h>
#include <stdio.h>
using namespace boost::fusion;

struct Foo_s { int i; typedef char j_t[10]; Foo_s::j_t j; };
BOOST_FUSION_ADAPT_STRUCT( Foo_s,  (int, i)  (Foo_s::j_t, j) )

struct Bar_s { int v; typedef Foo_s w_t[2]; Bar_s::w_t w; };
BOOST_FUSION_ADAPT_STRUCT( Bar_s, (int, v)  (Bar_s::w_t, w) )

template <typename T2> struct Dec_s;

template <typename S, typename N> struct Comma {
  static inline void comma() { printf(" , "); }
};
template <typename S> struct Comma<S, typename 
 boost::mpl::prior<typename boost::fusion::result_of::size<S>::type >::type> {
   static inline void comma() {}
};

template <typename S, typename N> struct DecImplSeqItr_s {
  typedef typename boost::fusion::result_of::value_at<S, N>::type current_t;
  typedef typename boost::mpl::next<N>::type next_t;
  typedef boost::fusion::extension::struct_member_name<S, N::value> name_t;
  static inline void decode(S& s) {
    printf("  \" %s \" ", name_t::call() );
    Dec_s<current_t>::decode(boost::fusion::at<N>(s));
    Comma<S, N>::comma();  // Insert comma or not    
    DecImplSeqItr_s<S, next_t>::decode(s);
  }
};
template <typename S>
struct DecImplSeqItr_s<S, typename boost::fusion::result_of::size<S>::type > {
    static inline void decode(S& s) { }
};
template <typename S>
struct DecImplSeqStart_s:DecImplSeqItr_s<S, boost::mpl::int_<0> > {};

template <typename S> struct DecImplSeq_s {
  typedef DecImplSeq_s<S> type;
  static void decode(S & s) {
    printf("  struct  start --- { --- \n");
    DecImplSeqStart_s<S>::decode(s);
    printf("  struct  done  --- } --- \n");
  };
};

template <typename T2> struct DecImplArray_s {
  typedef DecImplArray_s<T2> type;
  typedef typename boost::remove_bounds<T2>::type slice_t;
  static const size_t size = sizeof(T2) / sizeof(slice_t);
  static inline void decode(T2 & t) {
    printf("  array start --- [ --- \n");
    for(size_t idx=0; idx<size; idx++) { Dec_s<slice_t>::decode(t[idx]); }
    printf("  array done  --- ] --- \n");
  }
};

template <typename T2> struct DecImplVoid_s {
  typedef DecImplVoid_s<T2> type;
  static void decode(T2   & t) { 
    int status = 0;
    const char *realname = abi::__cxa_demangle(typeid(t).name(),0,0,&status);
    printf("  typename: %s  value: %s  realname: %s\n", typeid(t).name(),
           boost::lexical_cast(t).c_str(), realname);
  };
};

template <typename T2> struct DecCalc_s {
  typedef 
    typename boost::mpl::eval_if< traits::is_sequence<T2>, DecImplSeq_s<T2>, 
    typename boost::mpl::eval_if< boost::is_array<T2>, 
                                 boost::mpl::identity< DecImplArray_s<T2> >,
    DecImplVoid_s<T2>   > >
  ::type type;
};

template <typename T2> struct Dec_s : public DecCalc_s<T2>::type { };

int main(int argc, char *argv[]) {
  Bar_s f = { 2, {{ 3, "abcd" },{ 4, "defg" }} };
  Dec_s<Bar_s>::decode(f);
  return 0;
}
Advertisements

About minghuasweblog

a long time coder
This entry was posted in All, C/C++, Methods, Software and tagged , , , , . Bookmark the permalink.

2 Responses to Boost Fusion and Fusion.Adapt.Struct Example

  1. Pingback: Boost Fusion Adapt.Struct Part 2 – A Complete Example | minghuasweblog

  2. Hi, I tired your 2nd example. An exception is thrown when I run your 2nd example. Would you minding fixing the bug? The Boost version I used is 1.57 windows 32bits.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s