Boost Spirit中非Fusion适配结构的语义动作

3

假设我有一个简单的结构体,如下所示:

struct huh { char xxx; };  

如果不使用 Boost Fusion 适配的结构体,我想找到一个更简单的代理来操作 Spirit 规则语义动作中的成员变量。当然,这并不起作用:

_val.xxx = _1

但我希望能更加简洁的绑定Phoenix:

bind(&huh::xxx, _val) =  _1 

这里是一个可以在clang和g++编译器上运行的简单图片示例:

#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/phoenix/bind/bind_member_variable.hpp>

struct huh { char xxx; };

int main() {
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    namespace phx   = boost::phoenix;

    qi::rule<std::string::const_iterator, huh(), ascii::space_type> start;

    start =  qi::char_[
        phx::bind(&huh::xxx, qi::_val) =  qi::_1 
    ];

    return 0;
}

有什么想法吗?

这是我之前尝试过的一些愚蠢的东西。使用它,您可以像qi::char_[my_val.xxx=qi::_1]这样使用。您需要使用一个适配宏,因此如果这是您的问题,则此解决方案将无法帮助您。 - llonesmiz
1个回答

2

使用融合(Fusion)进行绑定,比使用凤凰(Phoenix)更加"干净一点",这正是将它们粘合在一起的方法。

因此,你就有了解决方案。或者,你也可以考虑分解你的表达式模板:

auto _xxx = phx::bind(&huh::xxx, _val);

所以你可以写成:

start =  char_[ _xxx = _1 ];

或者,使用函数或定制点:

定制点

添加特性

namespace boost { namespace spirit { namespace traits {

    template <> struct assign_to_attribute_from_value<huh, char, void> {
        static void call(char c, huh& attr) { attr.xxx = c; }
    };

} } }

现在你可以简单地编写:

qi::rule<std::string::const_iterator, huh(), ascii::space_type> start;

start = qi::char_;

在 Coliru 上实时运行

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>

struct huh { char xxx; };

namespace boost { namespace spirit { namespace traits {

    template <> struct assign_to_attribute_from_value<huh, char, void> {
        static void call(char c, huh& attr) { attr.xxx = c; }
    };

} } }

int main() {
    namespace qi    = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    qi::rule<std::string::const_iterator, huh(), ascii::space_type> start;

    start = qi::char_;
}

添加了自定义点示例 在 Coliru 上实时运行 - sehe
自定义点方法更好,也可能更快,但它太丑了 :p。很遗憾没有宏或其他东西可以使编写变得更简单。 - llonesmiz
有一个,我会称之为BOOST_FUSION_ADAPT_STRUCT。在很多方面上 - sehe
我能否引你去看一下我认为很酷(如果它是由更好的程序员完成的)的东西? 它在上面的评论里(https://dev59.com/FY7ea4cB1Zd3GeqPDJYz#N5gToYgBc1ULPQZF1rmO)。 如果你决定去看,跳过(非常混乱的部分),直接去末尾看看它是如何使用的(很酷的部分)。 - llonesmiz
@cv_and_he 嗯,那会很酷,但我个人认为所需的努力不成比例(我会选择在我的答案中显示的auto val_xxx = phx::bind(&huh::xxx, _val);)。如果我们想要这个,我们应该基于未来的语言反射支持。$0.02 - sehe
感谢您提供的所有信息,尤其是作为第一次使用stackoverflow的用户。我必须同意,如果可以的话,BOOST_FUSION_ADAPT_STRUCT可能是正确的答案。这里的问题是处理外部和旧代码。此外,在公开的std::vector上调用成员函数(例如push_back)会逃离Fusion域。我的解决方案是编写一个解析器来提取并使Fusion适应大约300个结构体 :-) 尽管如此,auto _xxx对于那些更复杂的绑定特别有用。谢谢大家。 - Matt Hurd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接