是否可以将动作附加到boost :: spirit :: rule解析器,该解析器将解析后的结果分配给(尚未)未知实例的成员?

时间:2013-05-21 16:50:33

标签: c++ reference boost-spirit boost-bind boost-spirit-qi

我正在尝试从boost :: spirit规则定义的动作中引用(尚未)未知实例的成员,因此在伪代码中,

而不是     double_ [ref(rN)= _1] 我正在寻找类似的东西     X ** ppx;     double_ [ref(& X :: rN,ppx)= _1]

它的解决方法可能是一个简单的“语义操作”,其中包含一个知道实例并能够写入实例的参数,例如

qi::rule<Iterator, Skipper> start;
my_grammar(DataContext*& dataContext) : my_grammar::base_type(start) , execContext(execContext) {
    start = qi::double_[ boost::bind(&my_grammar::newValueForXY, dataContext, ::_1) ];

但是,我想知道是否有可能直接“绑定”到成员变量,就像可以通过使用“phoenix :: ref(...)= value”绑定到“本地”变量一样。

我尝试了以下语法:

start = qi::int_[ boost::bind<int&>(&DataContext::newValueForXY, boost::ref(dataContext))() = ::_1] ];

但VS2010SP1失败并出现错误消息

错误C2440:'=':'boost :: arg'无法转换为...

1 个答案:

答案 0 :(得分:9)

有几种方法可以遮盖这只猫:

  1. 您可能想过推迟执行绑定表达式phx::bind可以这样做
  2. 或者,你可以只使用属性传播(并且不用语义动作
  3. 最后,您可以使用继承的属性(例如,当DataContext没有默认构造函数或复制很昂贵时)
  4. 1。推迟与凤凰的结合

    出于此目的使用phoenix bind:这将导致Phoenix actor,在语义动作被触发时将被“延迟执行”。

    以下是您可能遇到的缺失代码示例的重建:

    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    
    namespace qi = boost::spirit::qi;
    namespace phx= boost::phoenix;
    
    struct DataContext
    {
        double xy;
    };
    
    template <typename Iterator, typename Skipper>
    struct my_grammar : qi::grammar<Iterator, Skipper>
    {
        my_grammar(DataContext& dataContext) : my_grammar::base_type(start)
        {
            start = qi::double_
                [ phx::bind(&my_grammar::newValueForXY, 
                        phx::ref(dataContext), 
                        qi::_1) ];
        }
      private:
        static void newValueForXY(DataContext& dc, double value)
        {
             dc.xy = value;
        }
    
        qi::rule<Iterator, Skipper> start;
    };
    
    int main()
    {
        const std::string s = "3.14";
    
        DataContext ctx;
    
        my_grammar<decltype(begin(s)), qi::space_type> p(ctx);
        auto f(begin(s)), l(end(s));
        if (qi::phrase_parse(f, l, p, qi::space))
            std::cout << "Success: " << ctx.xy << "\n";
    }
    

    注意:

    • phx :: ref()包装对datacontext的引用
    • qi :: _ 1而不是boost :: _ 1作为占位符
    • 考虑到newValueForXY的这种实现,您可以轻松编写

          start = qi::double_
              [ phx::bind(&DataContext::xy, phx::ref(dataContext)) = qi::_1 ];
      

    2。使用属性语法而不是语义动作

    但是,我可能会使用属性而不是语义操作来编写相同的示例(因为这基本上是它们用于):

    #include <boost/fusion/adapted/struct.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    
    namespace qi = boost::spirit::qi;
    namespace phx= boost::phoenix;
    
    struct DataContext {
        double xy;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(DataContext, (double, xy))
    
    template <typename Iterator, typename Skipper>
    struct my_grammar : qi::grammar<Iterator, DataContext(), Skipper>
    {
        my_grammar() : my_grammar::base_type(start) {
            start = qi::double_;
        }
      private:
        qi::rule<Iterator, DataContext(), Skipper> start;
    };
    
    int main()
    {
        const std::string s = "3.14";
        static const my_grammar<decltype(begin(s)), qi::space_type> p;
    
        DataContext ctx;
        if (qi::phrase_parse(begin(s), end(s), p, qi::space, ctx))
            std::cout << "Success: " << ctx.xy << "\n";
    }
    

    3。使用继承的属性传递上下文引用

    如果你绝对坚持,你甚至可以使用 inherited attributes

    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    
    namespace qi = boost::spirit::qi;
    namespace phx= boost::phoenix;
    
    struct DataContext {
        double xy;
    };
    
    template <typename Iterator, typename Skipper>
    struct my_grammar : qi::grammar<Iterator, void(DataContext&), Skipper> {
        my_grammar() : my_grammar::base_type(start) 
        {
            start = qi::double_ [ phx::bind(&DataContext::xy, qi::_r1) = qi::_1 ];
        }
        qi::rule<Iterator, void(DataContext&), Skipper> start;
    };
    
    int main() {
        const std::string s = "3.14";
        const static my_grammar<std::string::const_iterator, qi::space_type> p;
        DataContext ctx;
        if(qi::phrase_parse(begin(s), end(s), p(phx::ref(ctx)), qi::space)) {
            std::cout << "Success: " << ctx.xy << "\n";
        }
    }
    

    这在呼叫网站上更具表现力:

    qi::phrase_parse(begin(s), end(s), p(phx::ref(ctx)), qi::space));
    

    并且不要求上下文是默认可构造的。