开发者

Is there an alternative for boost::phoenix::at_c in combination with boost::spirit::qi::grammar

I have created a test application to illustrate my problem. It parses a list of integers preceded by "a=" or "b=" and is separated by "\r\n". The list contains multiple occurrences of those fields in any order.

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

#include <boost/spirit/include/qi.hpp>

#include <boost/spirit/include/phoenix.hpp>

#include <b开发者_JAVA百科oost/fusion/include/adapt_struct.hpp>


typedef std::vector<unsigned int> uint_vector_t;

std::ostream& operator<<(std::ostream& out, const uint_vector_t &data)
{
    for (unsigned int i(0); i < data.size(); i++)
    {
        out << data[i] << '\n';
    }
    return out;
}

struct MyStruct
{
    uint_vector_t m_aList;
    uint_vector_t m_bList;
};

BOOST_FUSION_ADAPT_STRUCT
(
    MyStruct,
    (uint_vector_t, m_aList)
    (uint_vector_t, m_bList)
)
;

template<typename Iterator>
struct MyParser : public boost::spirit::qi::grammar<Iterator,
        MyStruct()>
{
    MyParser() :
        MyParser::base_type(Parser, "Parser")
    {
        using boost::spirit::qi::uint_;
        using boost::spirit::qi::_val;
        using boost::spirit::qi::_1;

        using boost::phoenix::at_c;
        using boost::phoenix::push_back;

        Parser =
                *(
                        aParser [push_back(at_c<0>(_val), _1)]
                    |
                        bParser [push_back(at_c<1>(_val), _1)]
                );
        aParser = "a=" >> uint_ >> "\r\n";
        bParser = "b=" >> uint_ >> "\r\n";
    }
        boost::spirit::qi::rule<Iterator, MyStruct()> Parser;
        boost::spirit::qi::rule<Iterator, unsigned int()> aParser, bParser;
};

int main()
{
    using boost::spirit::qi::phrase_parse;

    std::string input("a=0\r\nb=7531\r\na=2\r\na=3\r\nb=246\r\n");
    std::string::const_iterator begin = input.begin();
    std::string::const_iterator end = input.end();
    MyParser<std::string::const_iterator> parser;

    MyStruct result;
    bool succes = phrase_parse(begin, end, parser, "", result);
    assert(succes);

    std::cout << "===A===\n" <<result.m_aList << "===B===\n" << result.m_bList << std::endl;
}

In practice there are more fields with different types which need to be parsed. My objection with this approach lies in the following expression: [push_back(at_c<0>(_val), _1)] Here is a 'hidden dependency' between the assignment and the first element of MyStruct. This makes the code fragile to changes. If the struct is changed it might still compile, but no longer do what is expected.

I'm hoping for a construction like: [push_back(at_c<0>bind(&MyStruct::aList, arg1)(_val), _1)] See this. So that it is really bound by name.

Is something like this possible? Or should I take a total different approach?


Phoenix allows you to bind data members as well, so you can write:

Parser = 
   *(  aParser [push_back(bind(&MyStruct::m_aList, _val), _1)] 
    |  bParser [push_back(bind(&MyStruct::m_bList, _val), _1)] 
    ); 

Moreover, in this case you don't need the FUSION_ADAPT magic for your structure anymore.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜