[英]How to use std::function in a qi symbol table
我有以下代碼。 此代碼應解析兩個 int 並將比較結果作為 bool 返回。 為了比較,我使用 qi::symbol 表。 但是,不幸的是,它不能編譯。 知道出了什么問題嗎?
#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
。
語義動作需要是 Phoenix Actors。 換句話說,延遲或延遲 function 對象。
獲得它的方法通常是使用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 Function:
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)];
您可以用 std 函數替換 lambda:
sym.add
("==", std::equal_to<>{})
("!=", std::not_equal_to<>{});
或者如果你沒有 c++14
sym.add
("==", std::equal_to<int>{})
("!=", std::not_equal_to<int>{});
如果您想要異構評估(不僅僅是 boolean 謂詞)、一元運算符、優先級、關聯性,請查看我在此站點上制作的一些示例。
通常他們將評估階段與解析階段分開:
但是,如果您願意,您確實可以將解析與評估結合起來。 在這種情況下,將所有內容簡化為直接在語義操作中是有意義的:
#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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.