c ++/boost融合处理父类 [英] c++/boost fusion handle parent class

查看:101
本文介绍了c ++/boost融合处理父类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有这样的类层次结构:

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; }
};

全部使用单继承性从Base派生而未定义 任何virtual方法,但覆盖type()方法除外.

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

我想为每个从Base派生到序列化和调试输出的元信息.正如我所见,增强融合是我想要的:

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);
}

但是如何处理Base数据成员? 我不想将它们的描述包含在BOOST_FUSION_ADAPT_STRUCT(Foo1中, 像这样:

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))

因为我必须对从Base继承的每个结构都执行此操作, 因此,我希望使用与此类似的语法(当然不进行编译):

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?

推荐答案

您需要分别处理Fusion序列,例如使用SFINAE:

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";
}

IsSeq<Index>辅助特征的实现如下.现在您可以使用:

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)

并获得

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

实时演示

在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);
}

这篇关于c ++/boost融合处理父类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆