c++/boost fusion handle parent class

匿名 (未验证) 提交于 2019-12-03 01:00:01

问题:

Lets suppose I have such classes hierarchy:

enum class Type { DUMMY }; struct Base {   int a;   explicit Base(int a) : a(a) {}   virtual ~Base() {}   virtual Type type() = 0; };  struct Foo1 : public Base {   double b;   Foo1(int a, double b) : Base{a}, b(b) {}   Type type() override { return Type::DUMMY; } };

all derived from Base using single inheritance and not defined any virtual methods, except overriding type() method.

And I want to have meta info for each derived from Base to serialization and debug output. And as I see boost fusion is what I want:

#include <iostream> #include <string>  #include <boost/fusion/include/adapt_struct.hpp> #include <boost/fusion/include/at_c.hpp> #include <boost/fusion/include/for_each.hpp> #include <boost/fusion/include/mpl.hpp> #include <boost/fusion/include/zip.hpp> #include <boost/mpl/range_c.hpp>  namespace fusion = boost::fusion; namespace mpl = boost::mpl;  enum class Type { DUMMY }; struct Base {   int a;   explicit Base(int a) : a(a) {}   virtual ~Base() {}   virtual Type type() = 0; };  struct Foo1 : public Base {   double b;   Foo1(int a, double b) : Base{a}, b(b) {}   Type type() override { return Type::DUMMY; } };  BOOST_FUSION_ADAPT_STRUCT(Foo1, (double, b))  template <typename Sequence> struct XmlFieldNamePrinter {   XmlFieldNamePrinter(const Sequence &seq) : seq_(seq) {}   const Sequence &seq_;   template <typename Index> void operator()(Index idx) const {      std::string field_name =         fusion::extension::struct_member_name<Sequence, idx>::call();      std::cout << '<' << field_name << '>' << fusion::at<Index>(seq_) << "</"               << field_name << ">\n";     ;   } }; template <typename Sequence> void printXml(Sequence const &v) {   typedef mpl::range_c<unsigned, 0, fusion::result_of::size<Sequence>::value>       Indices;   fusion::for_each(Indices(), XmlFieldNamePrinter<Sequence>(v)); }  int main() {   Foo1 saveMe = {3, 3.4};   printXml(saveMe); }

But how handle Base data memebers? I do not want include their description into BOOST_FUSION_ADAPT_STRUCT(Foo1, like this:

BOOST_FUSION_ADAPT_STRUCT(Foo1,               (int, a)               (double, b))

because of I have to do it for every struct that inherit from Base, so I would prefer syntax similar to this(not compiled of course):

BOOST_FUSION_ADAPT_STRUCT(Base, (int, a))  BOOST_FUSION_ADAPT_STRUCT(Foo1,               (Base, __parent__)               (double, b))

How can I achieve similar syntax?

回答1:

You need to treat Fusion sequences separately, e.g. using SFINAE:

template <typename Index, typename IsSeq = IsSeq<Index> > typename boost::disable_if<IsSeq, void>::type operator()(Index idx) const {     std::string field_name = fusion::extension::struct_member_name<Sequence, idx>::call();      std::cout << '<' << field_name << '>' << fusion::at<Index>(seq_) << "</" << field_name << ">\n"; }  template <typename Index, typename IsSeq = IsSeq<Index> > typename boost::enable_if<IsSeq, void>::type operator()(Index idx) const {     std::string field_name = fusion::extension::struct_member_name<Sequence, idx>::call();      std::cout << "<" << field_name << ">\n\t";      typedef typename IsSeq::sequence_type SubSeq;     typedef mpl::range_c<unsigned, 0, fusion::result_of::size<SubSeq>::value> SubIndices;     fusion::for_each(SubIndices(), XmlFieldNamePrinter<SubSeq>(fusion::at<Index>(seq_)));      std::cout << "</" << field_name << ">\n"; }

The implementation of the IsSeq<Index> helper trait is below. Now you can use:

BOOST_FUSION_ADAPT_STRUCT(Base, a) BOOST_FUSION_ADAPT_STRUCT(Foo1, base, b)

And get

<base>     <a>3</a> </base> <b>3.4</b>

LIVE DEMO

Live On Coliru

#include <iostream> #include <string>  #include <boost/fusion/include/adapt_struct.hpp> #include <boost/fusion/include/at_c.hpp> #include <boost/fusion/include/for_each.hpp> #include <boost/fusion/include/mpl.hpp> #include <boost/fusion/include/zip.hpp> #include <boost/mpl/range_c.hpp>  namespace fusion = boost::fusion; namespace mpl = boost::mpl;  enum class Type { DUMMY }; struct Base {     int a;     explicit Base(int a) : a(a) {}     virtual ~Base() {}     virtual Type type() = 0;      Base &base = *this; };  struct Foo1 : public Base {     double b;     Foo1(int a, double b) : Base{ a }, b(b) {}     Type type() override { return Type::DUMMY; } };  BOOST_FUSION_ADAPT_STRUCT(Base, a) BOOST_FUSION_ADAPT_STRUCT(Foo1, base, b)  template <typename Sequence> struct XmlFieldNamePrinter {     XmlFieldNamePrinter(const Sequence &seq) : seq_(seq) {}     const Sequence &seq_;      template <typename Index,              typename T = typename fusion::result_of::at_c<Sequence, Index::value>::type,              typename BareT = typename boost::remove_reference<T>::type         >     struct IsSeq : mpl::bool_<fusion::traits::is_sequence<BareT>::value> {         typedef BareT sequence_type; // if true_     };      template <typename Index, typename IsSeq = IsSeq<Index> >     typename boost::disable_if<IsSeq, void>::type operator()(Index idx) const {         std::string field_name = fusion::extension::struct_member_name<Sequence, idx>::call();          std::cout << '<' << field_name << '>' << fusion::at<Index>(seq_) << "</" << field_name << ">\n";     }      template <typename Index, typename IsSeq = IsSeq<Index> >     typename boost::enable_if<IsSeq, void>::type operator()(Index idx) const {         std::string field_name = fusion::extension::struct_member_name<Sequence, idx>::call();          std::cout << "<" << field_name << ">\n\t";          typedef typename IsSeq::sequence_type SubSeq;         typedef mpl::range_c<unsigned, 0, fusion::result_of::size<SubSeq>::value> SubIndices;         fusion::for_each(SubIndices(), XmlFieldNamePrinter<SubSeq>(fusion::at<Index>(seq_)));          std::cout << "</" << field_name << ">\n";     } };  template <typename Sequence> void printXml(Sequence const &v) {     typedef mpl::range_c<unsigned, 0, fusion::result_of::size<Sequence>::value> Indices;     fusion::for_each(Indices(), XmlFieldNamePrinter<Sequence>(v)); }  int main() {     Foo1 saveMe = { 3, 3.4 };     printXml(saveMe); }


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!