Boost-Spirit (X3) parsing without default constructors

怎甘沉沦 提交于 2019-12-21 23:57:13

问题


I'm trying to use Spirit X3 from Boost 1.65.1 to make a parser. I have reduced my problem to the following smaller example with simpler structures:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include <iostream>
#include <vector>

struct MyPair {
    MyPair(int x, int y) : mx(x), my(y) {};
    //MyPair() {} // No default constructor - neither needed nor wanted.
    int mx;
    int my;
};

/*
BOOST_FUSION_ADAPT_STRUCT(
    MyPair,
    (int, mx)
    (int, my)
)
*/

int main()
{
    using boost::spirit::x3::int_;
    using boost::spirit::x3::parse;

    std::vector<MyPair> pairs;
    char const *first = "11:22,33:44,55:66", *last = first + std::strlen(first);
    auto pair = [&](auto& ctx) { return MyPair(1, 2); };
    bool parsed_some = parse(first, last, ((int_ >> ':' >> int_)[pair]) % ',', pairs);

    if (parsed_some) {
        std::cout << "Parsed the following pairs" << std::endl;
        for (auto& p : pairs) {
            std::cout << p.mx << ":" << p.my << std::endl;
        }
    }
    return 0;
}

I do not want to add a default constructor to my type (here MyPair). Without a default constructor I get the following error:

'MyPair::MyPair': no appropriate default constructor available  ...\boost\utility\value_init.hpp

But I do not want to change my structures to have a default constructor. Suppose, I do add one, the last error I get is:

binary '=': no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion) TestParsing ...\x3\support\traits\move_to.hpp 

But since I manually construct the attribute in a semantic action I do not see why I need to make a fusion definition. (Note, that currently it uses hardcoded values, until I get this problem fixed, and then get the proper value out).

How do I construct attributes of user-defined type without default constructors using Spirit X3?


回答1:


The only way that comes to mind is too avoid having a rule/parser that binds to a MyPair attribute at all.

Fortunately X3 is flexible enough to bind to a container attribute repeatedly:

auto pair = x3::rule<struct pair_, std::vector<MyPair> > {} 
          = (int_ >> ':' >> int_) 
              [([&](auto& ctx) { 
                  auto& attr = x3::_attr(ctx);
                  using boost::fusion::at_c;
                  return x3::_val(ctx).emplace_back(at_c<0>(attr), at_c<1>(attr));
              })]
          ;

Live On Coliru

#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <vector>

struct MyPair {
    MyPair(int x, int y) : mx(x), my(y) {};
    int mx;
    int my;
};

int main()
{
    namespace x3 = boost::spirit::x3;
    using x3::int_;

    std::vector<MyPair> pairs;
    char const *first = "11:22,33:44,55:66", *last = first + std::strlen(first);

    auto pair = x3::rule<struct pair_, std::vector<MyPair> > {} 
              = (int_ >> ':' >> int_) 
                  [([&](auto& ctx) { 
                      auto& attr = x3::_attr(ctx);
                      using boost::fusion::at_c;
                      return x3::_val(ctx).emplace_back(at_c<0>(attr), at_c<1>(attr));
                  })]
              ;

    bool parsed_some = parse(first, last, pair % ',', pairs);

    if (parsed_some) {
        std::cout << "Parsed the following pairs" << std::endl;
        for (auto& p : pairs) {
            std::cout << p.mx << ":" << p.my << std::endl;
        }
    }
}

Prints

Parsed the following pairs
11:22
33:44
55:66


来源:https://stackoverflow.com/questions/46854389/boost-spirit-x3-parsing-without-default-constructors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!