我有以下代码。 这段代码将解析两个int,并将比较结果作为bool返回。 为了进行比较,我使用QI::符号表。 但不幸的是,它无法编译。 知道哪里出了问题吗?
#include <boost/spirit/include/qi.hpp>
int main(sint32 argc, char **argv)
{
boost::spirit::qi::symbols<char, std::function<bool(int, int)>> sym;
sym.add
("==", [](int v1, int v2) {return v1 == v2; })
("!=", [](int v1, int v2) {return v1 != v2; });
bool result;
std::string s("1==2");
namespace qi = boost::spirit::qi;
qi::phrase_parse(s.begin(), s.end(), (qi::int_ >> sym >> qi::int_)[qi::_val = boost::bind(qi::_2, qi::_1, qi::_3)], qi::space, result);
}
首先,不要在语义动作中使用boost::bind
。
语义动作需要是凤凰行动者。 换句话说,延迟或惰性函数对象。
通常使用Boost::Phoenix::bind
来获得这个值,但是在本例中,您的操作失败了:绑定不需要一个占位符,并且不知道如何绑定到它。
相反,让符号表公开延迟函数。 但是,您需要高级技巧来保护内部绑定不受外部绑定的影响:使用Boost::bind将回调发布到任务队列
相反,我建议在一个自定义的惰性操作中完成整个计算:
auto bin_eval = [](auto const& lhs, auto const& op, auto const& rhs) {
return op(lhs, rhs);
};
后来呢
(qi::int_ >> sym >> qi::int_)
[qi::_val = px::bind(bin_eval, _1, _2, _3)],
然而,这还不是全部。 您的示例可能过于简化了,因为它甚至无法使用正确的语义操作进行编译。 相反,您需要取消属性传播,这只会在向规则添加语义操作时发生:
住在科里鲁
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
int main() {
qi::symbols<char, std::function<bool(int, int)>> sym;
sym.add
("==", [](int v1, int v2) {return v1 == v2; })
("!=", [](int v1, int v2) {return v1 != v2; });
using namespace qi::labels;
bool result;
auto bin_eval = [](auto const& lhs, auto const& op, auto const& rhs) {
return op(lhs, rhs);
};
qi::rule<std::string::const_iterator, bool(), qi::space_type> rule;
rule = (qi::int_ >> sym >> qi::int_)
[qi::_val = px::bind(bin_eval, _1, _2, _3)];
for (std::string const s : {"1==2", "1!=2" }) {
std::cout << std::quoted(s) << " -> ";
if (qi::phrase_parse(s.begin(), s.end(), rule, qi::space, result)) {
std::cout << "result: " << std::boolalpha << result << "\n";
} else {
std::cout << "parse failed\n";
}
}
}
打印
"1==2" -> result: false
"1!=2" -> result: true
若要获得奖励积分,请将其提升到适当的Phoenix函数:
struct bin_eval_t {
template <typename T, typename U, typename V>
auto operator()(T const& lhs, U const& op, V const& rhs) const {
return op(lhs, rhs);
}
};
// ...
px::function<bin_eval_t> bin_eval;
// ...
rule = (qi::int_ >> sym >> qi::int_)
[qi::_val = bin_eval(_1, _2, _3)];
您可以将lambdas替换为std functional:
sym.add
("==", std::equal_to<>{})
("!=", std::not_equal_to<>{});
或者如果没有C++14
sym.add
("==", std::equal_to<int>{})
("!=", std::not_equal_to<int>{});
如果你想要异构的求值(不仅仅是布尔谓词),一元运算符,优先级,关联性,看看我在这个站点上做的一些例子。
通常它们将评估阶段与解析阶段分开:
但是,如果您愿意,您确实可以将解析与求值结合起来。 在这种情况下,将所有内容简化为直接在语义动作中是有意义的:
住在科里鲁
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
int main() {
using namespace qi::labels;
for (std::string const s : {"1==2", "1!=2" }) {
std::cout << std::quoted(s) << " -> ";
bool result;
if (qi::phrase_parse(s.begin(), s.end(),
qi::int_ >> (
"==" >> qi::int_ [ _val = (_val == _1) ]
| "!=" >> qi::int_ [ _val = (_val != _1) ]
),
qi::space,
result))
{
std::cout << "result: " << std::boolalpha << result << "\n";
} else {
std::cout << "parse failed\n";
}
}
}
打印
"1==2" -> result: false
"1!=2" -> result: true