Boost.Spirit.x3避免将相同类型的两个连续属性折叠到向量中

Rus*_*ene 9 c++ boost boost-spirit c++14 boost-spirit-x3

我正在努力学习Boost.Spirit,但我发现了一个难点.

我试图将字符串解析为以下结构:

struct employee {
    std::string name;
    std::string location;
};
Run Code Online (Sandbox Code Playgroud)

似乎当两个具有相同类型的属性背靠背时,它们会崩溃(逻辑上)std::vector为该类型的一个.由于该规则,以下解析器

+x3::ascii::alnum >>
    +x3::space >>
    +x3::ascii::alnum
Run Code Online (Sandbox Code Playgroud)

会有的属性std::vector<std::string>.

但我试图将其解析为struct,这意味着我的理想属性将是一个boost::fusion::tuple<std::string, std::string>,所以我可以调整我的结构.

不工作代码的完整版本(如上所述):

// Example program
#include <iostream>
#include <string>

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


struct employee {
    std::string name;
    std::string location;
};

BOOST_FUSION_ADAPT_STRUCT(employee, 
    (std::string, name),
    (std::string, location)
)

namespace x3 = boost::spirit::x3;

x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def = 
    +x3::ascii::alnum >>
    +x3::space >>
    +x3::ascii::alnum
    ;
BOOST_SPIRIT_DEFINE(parse_emp);

int main()
{
    std::string input = "Joe Fairbanks";

    employee ret;

    x3::parse(input.begin(), input.end(), parse_emp, ret);

    std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

现场观看

此代码触发static_assert告诉我我的属性不正确:

error: static_assert failed "Attribute does not have the expected size."
Run Code Online (Sandbox Code Playgroud)

随着命令

clang++ -std=c++14 test.cpp
Run Code Online (Sandbox Code Playgroud)

(它也在海湾合作委员会下失败).

我试过了什么

我找到了解决这个问题的方法,但它很混乱,我无法相信这是最干净的方法:

// Example program
#include <iostream>
#include <string>

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


struct employee {
    std::string name;
    std::string location;
};

namespace x3 = boost::spirit::x3;

x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def = 
    x3::eps [
    ([](auto& ctx) {
        x3::_val(ctx) = employee{};
    })
    ]>>
    (+x3::ascii::alnum)[
    ([](auto& ctx) {
        x3::_val(ctx).name = x3::_attr(ctx);
    })
    ]>>
    +x3::space >>
    (+x3::ascii::alnum)[
    ([](auto& ctx) {
        x3::_val(ctx).location = x3::_attr(ctx);
    })
    ]
    ;
BOOST_SPIRIT_DEFINE(parse_emp);

int main()
{
    std::string input = "Joe Fairbanks";

    employee ret;

    x3::parse(input.begin(), input.end(), parse_emp, ret);

    std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

现场观看

我真的不喜欢这个解决方案:它有点破坏了精神的惊人表现力并使它变得非常难看,如果我想在employee结构中添加新的字段,那么我必须添加一个额外的lambda,而不仅仅是更新我的BOOST_FUSION_ADAPT_STRUCT,这更容易.

所以问题是:是否有某种方法(希望)干净地将两个相同类型的连续属性从std::vector和分成boost::fusion::vector

提前感谢您获取此信息;).

ild*_*arn 6

问题是,与字符文字不同,它x3::space有一个属性.因此,您没有由空格分隔的两个单独字符序列的属性,而是包含空格的一个大字符序列的属性.

omit指令就是您所追求的,只需添加一个"非工作代码"即可.: - ]

// Example program
#include <string>
#include <iostream>

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

namespace x3 = boost::spirit::x3;

struct employee {
    std::string name;
    std::string location;
};
BOOST_FUSION_ADAPT_STRUCT(employee, name, location)

x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def
    =      +x3::ascii::alnum
        >>  x3::omit[+x3::space]
        >> +x3::ascii::alnum
    ;
BOOST_SPIRIT_DEFINE(parse_emp)

int main()
{
    std::string const input = "Joe Fairbanks";

    employee ret;
    x3::parse(input.begin(), input.end(), parse_emp, ret);

    std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << '\n';
}
Run Code Online (Sandbox Code Playgroud)

Online Demo

  • 这是一个美好的一天,在我找到问题:) +1之前,精神问题的答案已经存在 (3认同)
  • @Russel我建议使用一个队长而不是显式空格(参见http://stackoverflow.com/questions/17072987/boost-spirit-skipper-issues/17073965#17073965).[住在Coliru](http://coliru.stacked-crooked.com/a/444dad3ed2859a35). (2认同)
  • @RussellGreene:`omit`具体_has no_属性,这是关键.`+ x3 :: ascii :: alnum >> +''>> + x3 :: ascii :: alnum`也可以正常工作,不需要`省略`,因为字符文字也没有属性. (2认同)