【问题标题】:Boost-Spirit (X3) parsing without default constructors没有默认构造函数的 Boost-Spirit (X3) 解析
【发布时间】:2017-10-20 17:31:53
【问题描述】:

我正在尝试使用 Boost 1.65.1 中的 Spirit X3 来制作解析器。我已将我的问题简化为以下结构更简单的较小示例:

#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;
}

我不想为我的类型(此处为 MyPair)添加默认构造函数。如果没有默认构造函数,我会收到以下错误:

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

但我不想将我的结构更改为具有默认构造函数。假设,我确实添加了一个,我得到的最后一个错误是:

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 

但是由于我在语义动作中手动构造了属性,所以我不明白为什么需要进行融合定义。 (注意,目前它使用硬编码值,直到我解决了这个问题,然后得到正确的值)。

如何使用 Spirit X3 在没有默认构造函数的情况下构造用户定义类型的属性?

【问题讨论】:

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


    【解决方案1】:

    想到的唯一方法就是完全避免使用绑定到MyPair 属性的规则/解析器。

    幸运的是,X3 足够灵活,可以重复绑定到容器属性:

    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;
            }
        }
    }
    

    打印

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

    【讨论】:

    • 谢谢。但我不确定我是否可以应用这种方法。我想要的输出“AST”是大多数非默认可构造类型的层次结构,例如: A a("Simple/Primitive argument") ... B b(24.8); //最低层 X x(a, c) .... Y y(b); //最低+1层 P(x, y) //最低+2层……以此类推.....
    • 那你会很难有精神。我会解析成一个中间表示并转换它。 X3 具有使转换“自动”的特性
    • 我担心我不得不做另一个中间表示;很多样板。您是否有一些关于如何自动化这些转换的文档的链接?
    • 通过排除自动化它们。如果您无法更改遗留类型,请编写自己的脚本来提供帮助(我的编辑器通常足够强大)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多