我是一名学习Boost.Spirit的初学者,但我遇到了困难。
我正在尝试将一个字符串解析成以下结构:
当两个相同类型的属性挨在一起时,它们会逻辑上合并成一个该类型的
使用命令:
我正在尝试将一个字符串解析成以下结构:
struct employee {
std::string name;
std::string location;
};
当两个相同类型的属性挨在一起时,它们会逻辑上合并成一个该类型的
std::vector
。由于这个规则,下面的解析器...+x3::ascii::alnum >>
+x3::space >>
+x3::ascii::alnum
这个属性应该是 std::vector<std::string>
。
但我正在尝试将其解析为struct
,这意味着对我来说理想的属性应该是boost::fusion::tuple<std::string, std::string>
,这样我就可以将我的结构体适应它。
不起作用的代码的完整版本(如上所述):
// Example program
#include <iostream>
#include <string>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
struct employee {
std::string name;
std::string location;
};
BOOST_FUSION_ADAPT_STRUCT(employee,
(std::string, name),
(std::string, location)
)
namespace x3 = boost::spirit::x3;
x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def =
+x3::ascii::alnum >>
+x3::space >>
+x3::ascii::alnum
;
BOOST_SPIRIT_DEFINE(parse_emp);
int main()
{
std::string input = "Joe Fairbanks";
employee ret;
x3::parse(input.begin(), input.end(), parse_emp, ret);
std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}
这段代码会触发一个static_assert
,告诉我我的属性不正确:
error: static_assert failed "Attribute does not have the expected size."
使用命令:
clang++ -std=c++14 test.cpp
(在GCC下也失败了)。
我尝试了什么
我已经找到了一个解决这个问题的方法,但它很杂乱,我不相信这是最干净的方式:
// Example program
#include <iostream>
#include <string>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
struct employee {
std::string name;
std::string location;
};
namespace x3 = boost::spirit::x3;
x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def =
x3::eps [
([](auto& ctx) {
x3::_val(ctx) = employee{};
})
]>>
(+x3::ascii::alnum)[
([](auto& ctx) {
x3::_val(ctx).name = x3::_attr(ctx);
})
]>>
+x3::space >>
(+x3::ascii::alnum)[
([](auto& ctx) {
x3::_val(ctx).location = x3::_attr(ctx);
})
]
;
BOOST_SPIRIT_DEFINE(parse_emp);
int main()
{
std::string input = "Joe Fairbanks";
employee ret;
x3::parse(input.begin(), input.end(), parse_emp, ret);
std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}
我真的不喜欢那个解决方案:它有点破坏了 Spirit 的惊人表现力,并使其变得非常丑陋,而且如果我想将新字段添加到 employee
结构中,则必须添加额外的 lambda,而不是仅更新我的 BOOST_FUSION_ADAPT_STRUCT
,这要容易得多。
因此问题是:是否有一种方法可以(希望)将同一类型的两个连续属性从 std::vector
中清晰地拆分并放入 boost::fusion::vector
中?
感谢您预先阅读;)。
omit
特别是没有属性,这是关键。+x3::ascii::alnum >> +' ' >> +x3::ascii::alnum
也可以工作,无需使用omit
,因为字符字面量也没有属性。 - ildjarn