【问题标题】:Using Boost Spirit Qi qi::iter_pos but can't capture value使用 Boost Spirit Qi qi::iter_pos 但无法捕获值
【发布时间】:2019-05-02 19:39:36
【问题描述】:

我需要在我正在使用 Boost Spirit Qi 解析的文本中跟踪某些项目的位置。我找到了this example 并适应了这样:

#include <iostream>
#include <string>
#include <boost/spirit/home/qi.hpp>
#include <boost/spirit/repository/include/qi_iter_pos.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;

template<typename Iterator>
struct CurrentPos 
{
    CurrentPos() 
    {
        save_start_pos = qi::omit[boost::spirit::repository::qi::iter_pos[
                phx::bind(&CurrentPos::setStartPos, this, qi::_1)]];

        current_pos = boost::spirit::repository::qi::iter_pos[
                qi::_val = phx::bind(&CurrentPos::getCurrentPos, this, qi::_1)];
    }

    qi::rule<Iterator> save_start_pos;
    qi::rule<Iterator, std::size_t()> current_pos;

private:
    void setStartPos(const Iterator &iterator) 
    {
        start_pos_ = iterator;
    }

    std::size_t getCurrentPos(const Iterator &iterator) 
    {
        return std::distance(start_pos_, iterator);
    }

    Iterator start_pos_;
};

using InfoTuple = std::tuple<std::size_t, std::uint32_t>;

struct Header
{
    std::uint32_t x;
    InfoTuple y;
};

BOOST_FUSION_ADAPT_STRUCT(
    Header,
    (std::uint32_t, x)
    (InfoTuple, y)
)

template<typename Iterator>
struct HeaderParse
    : boost::spirit::qi::grammar<Iterator, Header()>
{
    HeaderParse()
        : HeaderParse::base_type(_start)
    {
        using boost::spirit::qi::uint_parser;

        _thing = (current_pos.current_pos >> uint_parser<std::uint32_t, 10, 1, 3>());
        _start = current_pos.save_start_pos 
            >> '<' 
            >> uint_parser<std::uint32_t, 10, 1, 3>() 
            >> '>'
            >> _thing;
    }   

    qi::rule<Iterator, InfoTuple()> _thing; 
    qi::rule<Iterator, Header()> _start;

    CurrentPos<Iterator> current_pos;
};

int main()
{
    const std::string d1 = "<13>937";

    const HeaderParse<std::string::const_iterator> parser;
    Header header;

    std::string::const_iterator begin = d1.begin();
    std::string::const_iterator end = d1.end();

    assert(boost::spirit::qi::parse(begin, end, parser, header));
    assert(begin == end);

    std::cout << "x    : " << header.x << std::endl;
    std::cout << "y    : " << std::get<1>(header.y) << std::endl;
    std::cout << "y pos: " << std::get<0>(header.y) << std::endl;
}

当我运行它时,我看到以下输出:

$> ./testme
x    : 13
y    : 0
y pos: 4

由于某种原因,它不会捕获值937

我在 Coliru 上试过这个,起初它没有编译,现在我不断收到“执行过期”。见这里:https://coliru.stacked-crooked.com/a/724c7fcd296c8803 但这让我怀疑它是否有效。我正在使用 clang,而 Coliru 正在使用 gcc。

有人可以提供任何关于为什么这不起作用的见解吗?

【问题讨论】:

    标签: c++ boost-spirit boost-spirit-qi


    【解决方案1】:

    由于缺少 Fusion std::tuple 集成标头 (boost/fusion/include/std_tuple.hpp),您的示例无法为我编译。添加后,示例编译并输出预期结果。 https://wandbox.org/permlink/wOf8JxnKKeBGCihk

    P.S:我建议不要在解析器中计算偏移量,它不会为您节省任何东西,存储迭代器本身具有相同的内存占用,但复杂性和痛苦更少。

    【讨论】:

    • 这不是第一次缺少标头(但代码仍然可以编译)导致我遇到 Spirit 问题。应该不会是最后一个。感谢您的帮助!
    • 当心:在使用流输入时(或者,在任何使用 multi_pass 适配器的情况下),存储迭代器的成本可能要高得多。参见例如stackoverflow.com/a/40515812/85371
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    • 1970-01-01
    相关资源
    最近更新 更多