如何在 qi 符号表中使用 std::function



我有以下代码。此代码应解析两个 int 并将比较结果作为布尔值返回。 为了进行比较,我使用 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 failedn";
}
}
}

指纹

"1==2" -> result: false
"1!=2" -> result: true

漂亮?

对于奖励积分,请提升到适当的凤凰功能:

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)];

简单?

您可以将 lambda 替换为 std 函数:

sym.add
("==", std::equal_to<>{})
("!=", std::not_equal_to<>{});

或者如果你没有 c++14

sym.add
("==", std::equal_to<int>{})
("!=", std::not_equal_to<int>{});

多?

如果你想要异构计算(不仅仅是布尔谓词(、一元运算符、优先级、关联性,看看我在这个网站上做的一些例子。

通常他们将评估阶段与解析阶段分开:

  • 这是最新、最完整的 https://github.com/sehe/qi-extended-parser-evaluator(针对此问题制作,如本聊天中详细讨论的那样(
  • 本网站上许多更简单的示例

但是,如果需要,您确实可以将解析与评估结合起来。在这种情况下,将所有内容简化为直接在语义操作中是有意义的:

住在科里鲁

#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 failedn";
}
}
}

指纹

"1==2" -> result: false
"1!=2" -> result: true

相关内容

最新更新