我可以读取一个文件,并在编译时构建hetereogenous对象? [英] Can I read a file and construct hetereogenous objects at compile time?

查看:135
本文介绍了我可以读取一个文件,并在编译时构建hetereogenous对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

情况:

YAML文件的名字包含异类对象列表,像这样:

YAML file containing list of heterogeneous objects by name, like so:

object: Foo
  name: Joe Bloggs
  age: 26
object: Bar
  location: UK

对象不从任何基类继承或共享任何类型的,他们似乎活起来的事实相互分开的关系。

Objects do not inherit from any base class or share any sort of relationship between each other apart from the fact that they appear to "live" together.

这可以包含任意数量的对象。如果需要,可用类型的列表可以在codeBase的一个类型存在。

This can contain any number of objects. The list of available types can exist in a typelist in the codebase if required.

在我的C ++的土地我有对象:

In my C++ land I have the objects:

struct Foo {
  Foo(std::string n, int a) : name(n), age(a) {}

  std::string name;
  int age;
};

struct Bar {
  Bar(std::string l) : location(l) {}

  std::string location;
};

和上编译我想要把这一YAML文件转换成的boost ::融合::矢量

And on compilation I want to turn that YAML file into a boost::fusion::vector:

boost::fusion::vector<Foo, Bar>(Foo("Joe Bloggs", 26), Bar("UK"));

或者

boost::fusion::vector<Foo, Bar>(make_obj<Foo>("Joe Bloggs", 26), make_obj<Bar>("UK"));

也可以是的std ::元组如果它使生活更轻松。

有关make_obj专业化可以根据需要对所有支持的对象存在。

Specializations for make_obj can exist for all supported objects if needed.

这可能吗?

愿意得到我的手脏与MPL /等先进的元编程如果需要的话,或者,我可以做这一切与constexpr?

Willing to get my hands dirty with the MPL / other advanced metaprogramming if need be, or, can I do all this with constexpr?

C ++版本是无后顾之忧,可以用树干锵C ++ 14,如果需要的话。

C++ version is no worry, can use trunk Clang C++14 if need be.

推荐答案

我看到两个主要的方法:

I see two main approaches:

您可以使用BOOST_FUSION_ADAPT_STRUCT并让您鱼与熊掌兼得。如果你适应你的结构可以静态迭代他们 - 其实书面code发生器@πάνταῥεῖ提及,但内嵌在C ++ code和在编译时间

You can use BOOST_FUSION_ADAPT_STRUCT and have your cake and eat it. If you adapt your structs you can statically iterate them - in fact writing that code generator that @πάνταῥεῖ mentioned, but inline with the C++ code and at compile time.

您可以有类型使用静态变量的约束。

You can have the types statically constrained using a variant.

  • Is it possible to generate a fusion map from an adapted struct? shows how to use fusion::extension::struct_member_name to dump generic structs adapted with Fusion (you can forget about the type name demangling because you don't require it)
  • Boost fusion sequence type and name identification for structs and class that shows XML-like output for Fusion adapted structs.

使用升压精神你可以为同一个结构语法:

Using Boost Spirit you can just create a grammar for the same structs:

    start   = *(label_(+"object") >> object_);
    object_ = foo_ | bar_;

    foo_    = "Foo" >> eol >> (
                (string_prop_(+"name") >> eol) ^
                (int_prop_(+"age") >> eol)
            );

    bar_    = "Bar" >> eol >> (
                (string_prop_(+"location") >> eol)
            );

    label_  = lit(_r1) >> ':';

    string_prop_ = label_(_r1) >> lexeme [ *(char_ - eol) ];
    int_prop_    = label_(_r1) >> int_;

现在这个解析为变体LT;富,酒吧和GT; 没有任何进一步的编码。它甚至允许名称年龄出现在随机顺序(或接受默认值)。当然,如果你不这样做的希望这种灵活性,替换 ^ &GT;&GT ; 在语法

Now this parses into variant<Foo, Bar> without any further coding. It even allows name and age to appear in random order (or to accept the default value). Of course if you don't want this flexibility, replace ^ with >> in the grammar.

下面是一个样本输入:

object: Foo
  name: Joe Bloggs
  age: 26
object: Foo
  age: 42
  name: Douglas Adams
object: Foo
  name: Lego Man
object: Bar
  location: UK

而这里的样品(调试)的尾部输出:

And here's the tail of sample (debug) output:

<success></success>
<attributes>[[[[J, o, e,  , B, l, o, g, g, s], 26], [[D, o, u, g, l, a, s,  , A, d, a, m, s], 42], [[L, e, g, o,  , M, a, n], 0], [[U, K]]]]</attributes>
</start>
Parse success: 4 objects
N4data3FooE (Joe Bloggs 26)
N4data3FooE (Douglas Adams 42)
N4data3FooE (Lego Man 0)
N4data3BarE (UK)

<大骨节病> 住在Coliru

#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/bind.hpp>
#include <fstream>

namespace qi  = boost::spirit::qi;
namespace phx = boost::phoenix;

namespace demo {
    struct visitor : boost::static_visitor<> {
        template<typename Seq>
            void operator()(std::ostream& os, Seq const& seq) const {
                os << typeid(Seq).name() << "\t" << boost::fusion::as_vector(seq);
            }
    };
}

namespace data {
    struct Foo {
        Foo(std::string n="", int a=0) : name(n), age(a) {}

        std::string name;
        int age;
    };

    struct Bar {
        Bar(std::string l="") : location(l) {}

        std::string location;
    };

    using object  = boost::variant<Foo, Bar>;
    using objects = std::vector<object>;

    std::ostream& operator<< (std::ostream& os, object const& o) {
        boost::apply_visitor(boost::bind(demo::visitor(), boost::ref(os), _1), o);
        return os;
    }
}

BOOST_FUSION_ADAPT_STRUCT(data::Foo,(std::string,name)(int,age))
BOOST_FUSION_ADAPT_STRUCT(data::Bar,(std::string,location))

template <typename It>
struct grammar : qi::grammar<It, data::objects(), qi::blank_type> {
    grammar() : grammar::base_type(start) {
        using namespace qi;

        start   = *(label_(+"object") >> object_);
        object_ = foo_ | bar_;

        foo_    = "Foo" >> eol >> (
                    (string_prop_(+"name") >> eol) ^
                    (int_prop_(+"age") >> eol)
                );

        bar_    = "Bar" >> eol >> (
                    (string_prop_(+"location") >> eol)
                );

        label_  = lit(_r1) >> ':';

        string_prop_ = label_(_r1) >> lexeme [ *(char_ - eol) ];
        int_prop_    = label_(_r1) >> int_;

        BOOST_SPIRIT_DEBUG_NODES((start)(object_)(foo_)(bar_)(label_)(string_prop_)(int_prop_));
    }
  private:
    qi::rule<It, data::objects(), qi::blank_type> start;
    qi::rule<It, data::object(),  qi::blank_type> object_;
    qi::rule<It, data::Foo(),     qi::blank_type> foo_;
    qi::rule<It, data::Bar(),     qi::blank_type> bar_;

    qi::rule<It, std::string(std::string), qi::blank_type> string_prop_;
    qi::rule<It, int(std::string), qi::blank_type>         int_prop_;
    qi::rule<It, void(std::string), qi::blank_type>        label_;
};

int main()
{
    using It = boost::spirit::istream_iterator;
    std::ifstream ifs("input.txt");
    It f(ifs >> std::noskipws), l;

    grammar<It> p;
    data::objects parsed;
    bool ok = qi::phrase_parse(f,l,p,qi::blank,parsed);
    if (ok)
    {
        std::cout << "Parse success: " << parsed.size() << " objects\n";
        for(auto& object : parsed)
            std::cout << object << "\n";
    } else
    {
        std::cout << "Parse failed\n";
    }

    if (f!=l)
        std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}

这篇关于我可以读取一个文件,并在编译时构建hetereogenous对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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