我正在尝试解析以下形式的字符串:
f 1 2 3 4 f 1 2 3 f 1 2 3 4 5
使用Boost Spirit,我有:
using boost::spirit::qi::uint_;
using boost::spirit::qi::double_;
using boost::spirit::qi::_1;
using boost::spirit::qi::phrase_parse;
using boost::spirit::ascii::space;
using boost::phoenix::ref;
using boost::phoenix::push_back;
std::vector<unsigned int> v;
r = phrase_parse(first_, last_,
// Begin grammar
(
'f' >> uint_[push_back(ref(v), _1)] >>*(uint_[push_back(ref(v), _1)])
)
,
// End grammar
space);// Begin grammar
但是,我遇到了一堆编译错误:
错误 C2064 术语不计算为采用 2 个参数的函数
错误 C2668 'boost::phoenix::ref':对重载函数的不明确调用
错误 C2780 'bool boost::spirit::qi::phrase_parse(Iterator &,Iterator,Expr &,const Skipper &,boost::spirit::qi::skip_flag)':需要 5 个参数 - 提供 3 个参数
不太确定出了什么问题,因为该表格只是遵循中给出的示例程序 提升精神文档。
另外,请注意,我正在将 boost 1_55 与 MSVC 2015 一起使用(无法真正更改这些)
对于“f”后固定数量的整数,以下编译和工作:
unsigned int v1 = 0, v2 = 0, v3 = 0;
r = phrase_parse(first_, last_,
// Begin grammar
(
'f' >> uint_[ref(v1) = _1]
>> uint_[ref(v2) = _1] >> uint_[ref(v3) = _1]
),
// End grammar
space);
您的代码不是自包含的,但我们可以猜测
ref
是模糊的,因为由于 std::ref
在命名空间 std::vector
中声明,因此将选择 std
:ADL。
因此,使用 using 声明不太自由(更卫生),这对我来说在 Boost 1.55.0 上编译得很好:
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/version.hpp>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
std::string values(std::vector<unsigned> const& v) {
std::string r = "[";
for (auto& el : v)
r += (r.length() > 1 ? "," : "") + std::to_string(el);
return r + "]";
}
int main() {
std::cout << "Boost: " << BOOST_VERSION << " Spirit: " << std::hex << SPIRIT_VERSION << std::dec
<< std::endl;
for (std::string const input :
{"f ", "f1", "f", "f-3", "f1f2", "f 1 2 3 4 1 2 3 1 2 3 4 5", "f 1 2 3 4 f 1 2 3 f 1 2 3 4 5"}) {
std::vector<unsigned int> v;
std::string::const_iterator first_ = input.begin(), last_ = input.end();
bool r = qi::phrase_parse( //
first_, last_,
('f' >> qi::uint_[px::push_back(px::ref(v), qi::_1)] >>
*(qi::uint_[px::push_back(px::ref(v), qi::_1)])),
qi::space);
std::cout << (r ? "OK" : "FAIL") << "\t" //
<< input << " -> " << values(v) //
<< " remain '" << std::string(first_, last_) << "'" //
<< std::endl;
}
}
使用 Boost 1.55/Spirit v2.53 进行本地测试:
但是,不需要任何复杂性。
任何序列
p >> *p
根据定义等价于 +p
bool r = qi::phrase_parse( //
first_, last_, //
'f' >> +qi::uint_[px::push_back(px::ref(v), qi::_1)], //
qi::space);
push-back(后插入)已经是容器属性的默认操作,那么为什么要有语义操作?
bool r = qi::phrase_parse(first_, last_, 'f' >> +qi::uint_, qi::space, v);
这具有完全相同的效果,但没有编译开销和代码复杂性。你一开始就不会遇到 ADL 障碍。
**在 Coliru 上直播**1
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/version.hpp>
namespace qi = boost::spirit::qi;
std::string values(std::vector<unsigned> const& v) {
std::string r = "[";
for (auto& el : v)
r += (r.length() > 1 ? "," : "") + std::to_string(el);
return r + "]";
}
int main() {
std::cout << "Boost: " << BOOST_VERSION << " Spirit: " << std::hex << SPIRIT_VERSION << std::dec
<< std::endl;
for (std::string const input :
{"f ", "f1", "f", "f-3", "f1f2", "f 1 2 3 4 1 2 3 1 2 3 4 5", "f 1 2 3 4 f 1 2 3 f 1 2 3 4 5"}) {
std::vector<unsigned int> v;
auto f = input.begin(), l = input.end();
bool r = qi::phrase_parse(f, l, 'f' >> +qi::uint_, qi::space, v);
std::cout << (r ? "OK" : "FAIL") << "\t" //
<< input << " -> " << values(v) //
<< " remain '" << std::string(f, l) << "'" //
<< std::endl;
}
}
打印完全相同的输出。
¹ 请注意简化如何消除了对现已弃用的 Phoenix 标头的依赖