提问人:Jaime Ivan Cervantes 提问时间:6/29/2020 最后编辑:ildjarnJaime Ivan Cervantes 更新时间:7/19/2020 访问量:381
使用 Boost Spirit X3 和 Fusion 解析具有单个成员的结构变体
Parsing variant of struct with a single member using Boost Spirit X3 and Fusion
问:
我正在尝试使用包含单个成员的融合适应结构类型来解析。经过几个小时的尝试找出问题,我能够用以下代码重现该问题:std::Variant
struct TestStruct {
float value;
};
BOOST_FUSION_ADAPT_STRUCT(TestStruct, value)
typedef std::variant<TestStruct, std:string> TestVariant;
auto TestStructRule = x3::rule<struct test_struct, TestStruct>{} = x3::float_ >> ",";
auto TestVariantRule = x3::rule<struct test_variant, TestVariant>{} = TestStruct | "default" >> x3::attr(std::String{"default"});
这会导致以下生成错误:
boost/boost/spirit/home/x3/support/traits/move_to.hpp:67:18: error: no viable overloaded '='
dest = std::move(fusion::front(src));
boost/boost/spirit/home/x3/support/traits/move_to.hpp:79:13: note: in instantiation of function template specialization 'boost::spirit::x3::traits::detail::move_to_plain<TestStruct, std::__1::variant<TestStruct, std::string> >' requested here
move_to_plain(std::forward<Source>(src), dest, is_single_element_sequence);
...
/Library/Developer/CommandLineTools/usr/include/c++/v1/variant:1214:12: note: candidate function not viable: no known conversion from 'typename remove_reference<float &>::type' (aka 'float') to 'const std::__1::variant<TestStruct, std::String>' for 1st argument
variant& operator=(const variant&) = default;
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/variant:1215:12: note: candidate function not viable: no known conversion from 'typename remove_reference<float &>::type' (aka 'float') to 'std::__1::variant<TestStruct, std::String>' for 1st argument
variant& operator=(variant&&) = default;
我发现令人困惑的是,如果我添加第二个成员,以下代码实际上会正确编译和运行:TestStruct
struct TestStruct {
float value1;
float value2; // <-- Added second member
};
BOOST_FUSION_ADAPT_STRUCT(TestStruct, value1, value2)
typedef std::variant<TestStruct, std:string> TestVariant;
auto TestStructRule = x3::rule<struct test_struct, TestStruct>{} = x3::float_ >> "," >> x3::float_ >> ",";
auto TestVariantRule = x3::rule<struct test_variant, TestVariant>{} = TestStruct | "default" >> x3::attr(std::String{"default"});
我还在 SO 上读到,当尝试使用旧版本的 Spirit 解析这些结构时,融合适应的单场结构存在已知问题。
使用 Spirit X3 解决(或绕过)此问题的最佳方法是什么?
答:
3赞
sehe
6/29/2020
#1
我不想说,但这是一个众所周知的限制,而且它不断出现。我已经放弃了尝试修复它。这是一种通常易于解决或避免的边缘情况。
例如,参见
- boost::spirit::x3 属性兼容性规则、直觉还是代码?
- 如何使用 spirit x3 将结果解析的结果移动到结构中
- https://github.com/boostorg/spirit/pull/178
在您的事业中,我可能会避免解析,而是解析为 .否则,请使用语义操作(而不是自动属性传播)来解析和传播它。TestStruct
float
我尝试并发现在这种特定情况下很难克服障碍(这似乎是“反向”问题,其中已经正确匹配的规则暴露了TestResult仍然会带来问题。显然,属性合成规则又错了)。
蛮 力
auto assign = [](auto& ctx) { _val(ctx) = _attr(ctx); };
手动执行属性传播:
auto test_struct
= x3::rule<struct test_struct, TestStruct>{}
= x3::float_ >> ",";
auto test_variant
= x3::rule<struct test_variant, TestVariant>{}
= test_struct [assign] | "default" >> x3::attr("default"s)[assign];
作品: Live On Coliru
事实上,“官方”传播看起来更像是¹
auto assign = [](auto& ctx) {
x3::traits::move_to(_attr(ctx), _val(ctx));
};
而且它似乎不起作用:Live On Coliru
¹ 但不完全是,在此之前有很多元编程条件
评论
1赞
Jaime Ivan Cervantes
6/30/2020
感谢您@sehe的回答,我最终使用了语义操作:TestStruct
[](auto&ctx){x3::_val(ctx).value = x3::_attr(ctx);};
评论