在我目前正在开发的解析器中,我正在编写一些大小相当重要的规则/“子解析器”。问题是:由于这个解析器可能需要编译器付出一定的努力并且可以具有一定的大小,因此我只想翻译和实例化它一次,从而编写像 boost 教程中解释的那样的规则。到目前为止,一切都很好。但是,该规则将被属性类型始终不同的不同解析器频繁重用。 我将用下面的简单示例来说明我的问题,该示例已经尝试过但无法构建。
my_rule
是必须可重用的规则。我希望它可用于
Foo
、Bar
和 Baz
的三种解析规则。它们各自代表了我可能遇到的可重用性的可能用例。到目前为止,如示例所示,我尝试对所有用例使用 boost::fusion::vector
通用属性,但这并不那么容易。构建了 Foo
和 Baz
的解析规则,但 Bar
的解析规则没有构建。因此,根据这个例子,我的问题是:如何使 my_rule
在每个用例中工作?使用什么作为属性?至少有可能吗?我准备好听到“不”。
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/binary.hpp>
namespace x3 = boost::spirit::x3;
struct Foo
{
int a;
int b;
};
struct Bar
{
int c;
int d;
int e;
};
struct Baz
{
int f;
Foo foo;
};
BOOST_FUSION_ADAPT_STRUCT(Foo, a, b);
BOOST_FUSION_ADAPT_STRUCT(Bar, c, d, e);
BOOST_FUSION_ADAPT_STRUCT(Baz, f, foo);
const auto my_rule =
x3::rule<class My_rule_tag, boost::fusion::vector<int, int>>{ "my-rule" } %=
x3::byte_ >> x3::byte_;
const auto foo_rule = x3::rule<class Foo_rule_tag, Foo>{ "foo-rule" } %=
my_rule;
const auto bar_rule = x3::rule<class Bar_rule_tag, Bar>{ "bar-rule" } %=
x3::byte_ >> my_rule;
const auto baz_rule = x3::rule<class Bar_rule_tag, Baz>{ "baz-rule" } %=
x3::byte_ >> my_rule;
int
main()
{
std::vector<std::uint8_t> frame{ 0x03, 0x06, 0x09 };
// Build OK
Foo foo1;
x3::parse(frame.begin(), frame.end(), foo_rule, foo1);
// Build NOK
Bar bar1;
x3::parse(frame.begin(), frame.end(), bar_rule, bar1);
// Build OK
Baz baz1;
x3::parse(frame.begin(), frame.end(), baz_rule, baz1);
return 0;
}
和reusable,您希望规则与调用位于相同的 TU 中。 正如您已经弄清楚的(请参阅
Baz
聚合
Foo
),关键是使属性类型与属性传播兼容。我能想到的最简单的事情:
住在Coliru
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/binary.hpp>
template <typename T> constexpr static T parse(auto const& frame, auto rule) {
T val;
parse(begin(frame), end(frame), rule, val);
return val;
}
struct Foo { int a, b; constexpr auto operator<=>(Foo const&) const = default; };
struct Bar { int c, d, e; constexpr auto operator<=>(Bar const&) const = default; };
struct Baz { int f; Foo foo; constexpr auto operator<=>(Baz const&) const = default; };
BOOST_FUSION_ADAPT_STRUCT(Foo, a, b)
BOOST_FUSION_ADAPT_STRUCT(Bar, c, d, e)
BOOST_FUSION_ADAPT_STRUCT(Baz, f, foo.a, foo.b)
// using Vec2 = boost::fusion::vector<int, int>;
namespace x3 = boost::spirit::x3;
auto const vec2_ = x3::byte_ >> x3::byte_;
auto const foo_rule = vec2_;
auto const bar_rule = x3::byte_ >> vec2_;
auto const baz_rule = x3::byte_ >> foo_rule;
int main() {
constexpr std::array<std::uint8_t, 3> frame{0x03, 0x06, 0x09};
assert((parse<Foo>(frame, foo_rule) == Foo{ 3, 6 }));
assert((parse<Bar>(frame, bar_rule) == Bar{ 3, 6, 9 }));
assert((parse<Baz>(frame, baz_rule) == Baz{ 3, {6, 9} }));
}
Baz
的改编!
如果你想要
{foo,bar,baz}_rule
正确编译防火墙:
住在科里鲁
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/binary.hpp>
template <typename T> constexpr static T parse(auto const& frame, auto rule) {
T val;
parse(begin(frame), end(frame), rule, val);
return val;
}
struct Foo { int a, b; constexpr auto operator<=>(Foo const&) const = default; };
struct Bar { int c, d, e; constexpr auto operator<=>(Bar const&) const = default; };
struct Baz { int f; Foo foo; constexpr auto operator<=>(Baz const&) const = default; };
BOOST_FUSION_ADAPT_STRUCT(Foo, a, b)
BOOST_FUSION_ADAPT_STRUCT(Bar, c, d, e)
BOOST_FUSION_ADAPT_STRUCT(Baz, f, foo)
// using Vec2 = boost::fusion::vector<int, int>;
namespace x3 = boost::spirit::x3;
auto const vec2_ = x3::byte_ >> x3::byte_;
auto const foo_rule = x3::rule<class Foo_rule_tag, Foo>{"foo_rule"} = vec2_;
auto const bar_rule = x3::rule<class Bar_rule_tag, Bar>{"bar_rule"} = x3::byte_ >> vec2_;
auto const baz_rule = x3::rule<class Baz_rule_tag, Baz>{"baz_rule"} = x3::byte_ >> foo_rule;
int main() {
constexpr std::array<std::uint8_t, 3> frame{0x03, 0x06, 0x09};
assert((parse<Foo>(frame, foo_rule) == Foo{ 3, 6 }));
assert((parse<Bar>(frame, bar_rule) == Bar{ 3, 6, 9 }));
assert((parse<Baz>(frame, baz_rule) == Baz{ 3, {6, 9} }));
}
如果“涉及”
vec2_
(可能是某种数据包标头),那么
要么像在 Baz 中那样进行聚合永远不值得的 它,特别是对于X3。编译时间已经非常短了,而且 显式实例化硬锁迭代器以及上下文类型, 通常会导致难以理解的链接器错误。 参见例如