Boost.Spirit を学習しようとしていますが、問題が見つかりました。
文字列を次の構造に解析しようとしています。
struct employee {
std::string name;
std::string location;
};
そして、同じタイプの 2 つの属性が背中合わせにある場合、それらは (論理的に)std::vector
そのタイプの に折りたたまれているようです。そのルールのため、次のパーサー
+x3::ascii::alnum >>
+x3::space >>
+x3::ascii::alnum
の属性を持つことになりますstd::vector<std::string>
。
しかし、私は this を that に解析しようとしてstruct
います。つまり、私にとって理想的な属性は aboost::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
構造体に新しいフィールドを追加したい場合は、私のBOOST_FUSION_ADAPT_STRUCT
,これははるかに簡単です。
問題は、同じタイプの 2 つの連続する属性を (できれば) と から にきれいに分割する方法がstd::vector
あるboost::fusion::vector
かどうかです。
ここまでやってくれてありがとう;)。