在 Boost Spirit 中解析后跟可变数量整数的字符

问题描述 投票:0回答:1

我正在尝试解析以下形式的字符串:

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);
boost boost-spirit
1个回答
0
投票

您的代码不是自包含的,但我们可以猜测

ref
是模糊的,因为由于
std::ref
在命名空间
std::vector
中声明,因此将选择
std
ADL

因此,使用 using 声明不太自由(更卫生),这对我来说在 Boost 1.55.0 上编译得很好:

住在 Coliru(c++11)

#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 进行本地测试:

旁注:不复杂

但是,不需要任何复杂性。

  1. 任何序列

    p >> *p
    根据定义等价于
    +p

    bool r = qi::phrase_parse(                                //
        first_, last_,                                        //
        'f' >> +qi::uint_[px::push_back(px::ref(v), qi::_1)], //
        qi::space);
    
  2. 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 标头的依赖

© www.soinside.com 2019 - 2024. All rights reserved.