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

won*_*ime 3 c++ reference boost-bind boost-spirit 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) ];
Run Code Online (Sandbox Code Playgroud)

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

我尝试了以下语法:

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

但是VS2010SP1和错误消息失败了

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

seh*_*ehe 9

有几种方法可以给这只猫上皮:

  1. 你可能想过推迟执行绑定表达式:phx::bind可以做到这一点
  2. 或者,您可以使用属性传播(并且完全没有语义操作)
  3. 最后,您可以使用继承的属性(例如,当DataContext没有默认构造函数或复制很昂贵时)

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";
}
Run Code Online (Sandbox Code Playgroud)

注意:

  • phx :: ref()包含对datacontext的引用
  • qi :: _ 1而不是boost :: _ 1作为占位符
  • 鉴于这种实现,newValueForXY你可以很容易地编写

        start = qi::double_
            [ phx::bind(&DataContext::xy, phx::ref(dataContext)) = qi::_1 ];
    
    Run Code Online (Sandbox Code Playgroud)

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";
}
Run Code Online (Sandbox Code Playgroud)

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";
    }
}
Run Code Online (Sandbox Code Playgroud)

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

qi::phrase_parse(begin(s), end(s), p(phx::ref(ctx)), qi::space));
Run Code Online (Sandbox Code Playgroud)

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