Boost.Spirit.x3 避免将同一类型的两个连续属性折叠成一个向量
Boost.Spirit.x3 avoid collapsing two consecutive attributes of the same type into a vector
我正在努力学习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;
}
我真的不喜欢那个解决方案:它有点破坏了精神的惊人表现力并使它变得非常丑陋,而且如果我想将新字段添加到 employee
结构中,那么我必须添加一个额外的 lambda,而不是仅仅更新我的 BOOST_FUSION_ADAPT_STRUCT
,这要容易得多。
所以问题是:是否有某种方法(希望)将相同类型的两个连续属性从 std::vector
干净地拆分为 boost::fusion::vector
?
提前感谢您走到这一步 ;)。
问题在于,与字符文字不同,x3::space
有一个属性。因此,您没有由空格分隔的两个单独字符序列的属性,而是包含空格的一个大字符序列的属性。
The omit
directive 就是您所追求的,加上这个单一的 'not working code' 就可以了。 :-]
// Example program
#include <string>
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;
struct employee {
std::string name;
std::string location;
};
BOOST_FUSION_ADAPT_STRUCT(employee, name, location)
x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def
= +x3::ascii::alnum
>> x3::omit[+x3::space]
>> +x3::ascii::alnum
;
BOOST_SPIRIT_DEFINE(parse_emp)
int main()
{
std::string const input = "Joe Fairbanks";
employee ret;
x3::parse(input.begin(), input.end(), parse_emp, ret);
std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << '\n';
}
我正在努力学习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;
}
我真的不喜欢那个解决方案:它有点破坏了精神的惊人表现力并使它变得非常丑陋,而且如果我想将新字段添加到 employee
结构中,那么我必须添加一个额外的 lambda,而不是仅仅更新我的 BOOST_FUSION_ADAPT_STRUCT
,这要容易得多。
所以问题是:是否有某种方法(希望)将相同类型的两个连续属性从 std::vector
干净地拆分为 boost::fusion::vector
?
提前感谢您走到这一步 ;)。
问题在于,与字符文字不同,x3::space
有一个属性。因此,您没有由空格分隔的两个单独字符序列的属性,而是包含空格的一个大字符序列的属性。
The omit
directive 就是您所追求的,加上这个单一的 'not working code' 就可以了。 :-]
// Example program
#include <string>
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;
struct employee {
std::string name;
std::string location;
};
BOOST_FUSION_ADAPT_STRUCT(employee, name, location)
x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def
= +x3::ascii::alnum
>> x3::omit[+x3::space]
>> +x3::ascii::alnum
;
BOOST_SPIRIT_DEFINE(parse_emp)
int main()
{
std::string const input = "Joe Fairbanks";
employee ret;
x3::parse(input.begin(), input.end(), parse_emp, ret);
std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << '\n';
}