我正在尝试从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'无法转换为...
答案 0 :(得分:9)
有几种方法可以遮盖这只猫:
phx::bind
可以这样做出于此目的使用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";
}
注意:
考虑到newValueForXY
的这种实现,您可以轻松编写
start = qi::double_
[ phx::bind(&DataContext::xy, phx::ref(dataContext)) = qi::_1 ];
但是,我可能会使用属性而不是语义操作来编写相同的示例(因为这基本上是它们用于):
#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";
}
如果你绝对坚持,你甚至可以使用 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));
并且不要求上下文是默认可构造的。