我可以读取一个文件,并在编译时构建hetereogenous对象? [英] Can I read a file and construct hetereogenous objects at compile time?
问题描述
情况:
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它可以生成从结构调整的融合地图吗?展示了如何使用
融合::扩展:: struct_member_name
转储适应与融合的通用结构(你可以忘了类型名称demangling,因为你并不需要它) - Boost融合序列类型和名称鉴定结构和类显示类似XML输出融合适应结构。
- 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屋!