【问题标题】:Parsing using boost Spirit into STL vector使用 boost Spirit 解析成 STL 向量
【发布时间】:2018-04-29 09:47:26
【问题描述】:

我正在学习 Boost Spirit 2,但我不明白为什么我不能将两个整数的序列解析为 int 的 STL 向量。从 >> 运算符 (here) 的文档中,我知道语法 int_ >> int_ 的属性应该是 vector<int>。从attribute notation documentation 我知道“vector<A> 的表示法代表任何 STL 容器 包含类型 A 的元素”。

然而,当我尝试向int_ >> int_ 添加一个以std::vector 作为其属性的操作时,编译失败。

在其他错误消息中,它显示:/usr/include/boost/bind/mem_fn_template.hpp:163:7: note: no known conversion for argument 2 from ‘boost::fusion::vector<int, int>’ to ‘const std::vector<int>&’

我知道this question(“让 boost::spirit::qi 使用 stl 容器”),但那里的解决方案 - 包括 std_tuple.hpp - 并没有改变任何东西。

这是为什么?

#include <iostream>
#include <string>
#include <vector>

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/bind.hpp>

namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    class ParserActions
    {
    public:
        void printivec (std::vector<int> const& ivec)
        {
            std::cout << "We see " << ivec.size() << " integers" << std::endl;
        }
    };

    template <typename Iterator>
    bool parse_ivec(Iterator first, Iterator last)
    {
        using ascii::space;

        ParserActions actionContainer;

        auto two_ints = (qi::int_ >> qi::int_);

        bool r = qi::parse(
            first,                          /*< start iterator >*/
            last,                           /*< end iterator >*/
            two_ints[boost::bind(&ParserActions::printivec,&actionContainer,_1)]
            );

        return first == last && r;
    }
}

int main()
{
    std::string str = "12 13";

    if (client::parse_ivec(str.begin(),str.end()))
        std::cout << "Parsing succeeded\n";
    else
        std::cout << "Parsing failed!\n";

    return 0;
}

【问题讨论】:

    标签: c++ parsing boost stdvector boost-spirit


    【解决方案1】:

    int_ &gt;&gt; int_ 合成一个 int, int 的元组。¹

    如果你想强制合成一个容器,可以用repeat(2) [ int_ ] 来表达。

    旁注:正如您将在下面看到的,即使绑定的属性是一个容器,也有属性兼容的空间,所以您不需要。

    旁注:带有解析器表达式的auto 正在询问未定义的行为:Assigning parsers to auto variables

    旁注:您的输入使用空格分隔符,但解析器没有。那永远都行不通。

    您的代码示例似乎与目标无关,所以这是我的小示例:

    1。 vector&lt;int&gt;:

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    using Vec = std::vector<int>;
    namespace qi = boost::spirit::qi;
    
    template <typename It> Vec parse_ivec(It first, It last) {
        Vec v;
        if (qi::phrase_parse(first, last,  qi::int_ >> qi::int_ >> qi::eoi, qi::space, v))
            return v;
        throw std::runtime_error("Parse failed");
    }
    
    Vec parse_ivec(std::string const& r) { return parse_ivec(begin(r), end(r)); }
    
    int main() {
        for (int i : parse_ivec("12 13")) {
            std::cout << i << "\n";
        }
    }
    

    打印

    12
    13
    

    2。适应结构

    或者,如果你想要一个结构,而不是std::vector&lt;&gt;

    Live On Coliru

    #include <boost/fusion/adapted/struct.hpp>
    struct Vec { int a, b; };
    BOOST_FUSION_ADAPT_STRUCT(Vec, a, b)
    
    #include <boost/spirit/include/qi.hpp>
    namespace qi = boost::spirit::qi;
    
    template <typename It> Vec parse_ivec(It first, It last) {
        Vec v;
        if (qi::phrase_parse(first, last,  qi::int_ >> qi::int_ >> qi::eoi, qi::space, v))
            return v;
        throw std::runtime_error("Parse failed");
    }
    
    Vec parse_ivec(std::string const& r) { return parse_ivec(begin(r), end(r)); }
    
    int main() {
        Vec vec = parse_ivec("12 13");
        std::cout << vec.a << " " << vec.b << "\n";
    }
    

    打印

    12 13
    

    3。 std::tuple&lt;int, int&gt;:

    Live On Coliru

    #include <boost/fusion/adapted/std_tuple.hpp>
    using Vec = std::tuple<int, int>;
    
    #include <boost/spirit/include/qi.hpp>
    namespace qi = boost::spirit::qi;
    
    template <typename It> Vec parse_ivec(It first, It last) {
        Vec v;
        if (qi::phrase_parse(first, last,  qi::int_ >> qi::int_ >> qi::eoi, qi::space, v))
            return v;
        throw std::runtime_error("Parse failed");
    }
    
    Vec parse_ivec(std::string const& r) { return parse_ivec(begin(r), end(r)); }
    
    int main() {
        Vec vec = parse_ivec("12 13");
        std::cout << std::get<0>(vec) << " " << std::get<1>(vec) << "\n";
    }
    

    打印

    12 13
    

    ¹ 从技术上讲,它是一个 Fusion 序列,它可以与许多类型(如 std::pair)兼容,或者您​​自己的类型进行调整。

    【讨论】:

    • 谢谢!这些工作(当然)。第一个示例是我试图实现的目标,但我确实希望有几个与之相关的规则和操作。我会尝试更多...
    • 是的。欢迎您提出其他问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 2012-05-12
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    相关资源
    最近更新 更多