Boost Spirit Qi自定义同步属性(通过语义操作设置struct属性的特定成员)

nam*_*ero 6 c++ attributes boost-spirit boost-spirit-qi synthesize

假设我有一个我想用Spirit Qi解析的结构,定义如下:

struct data_
{
    bool export;
    std::wstring name;

    data_() : export(false) {}
};
Run Code Online (Sandbox Code Playgroud)

另外,假设结构已适应融合,如下所示:

BOOST_FUSION_ADAPT_STRUCT(
    data_,
    (bool, export)
    (std::wstring, name)
)
Run Code Online (Sandbox Code Playgroud)

相关规则是:

qi::rule<Iterator, data_(), skipper<Iterator> > rule_data;

rule_data = -lexeme["SpecialText" >> !(alnum | '_')] [ boost::phoenix::at_c<0> = true ] // If this string is found, , set "export" to true
            > lexeme["Name" >> !(alnum | '_')] // this is supposed to go into the "name" member
Run Code Online (Sandbox Code Playgroud)

到目前为止,这编译得非常好.但是,"名字"现在保持空白!

基本上,我问:鉴于"SpecialText"在"Name"之前,我如何正确地合成"export"的布尔属性,而不是字符串?

编辑 把我的头发拉出来之后,我随机偶然发现了"匹配[]"解析器,这似乎做了我想要的.

尽管如此,问题仍然存在于一般形式中,例如,如果我想返回某个字符串或其他数据类型而不是bool.本质上,如何通过语义操作设置struct属性的特定成员.

seh*_*ehe 11

如何设置结构成员.

选项1(phx::bind)

给定一个结构 S

struct S
{
    int         field1;
    std::string field2;
    int         target_field;
    bool        field3;
};
Run Code Online (Sandbox Code Playgroud)

您可以target_field像这样指定一个字段(例如):

rule<It, S()> p = int_ [ phx::bind(&S::target_field, _val) = _1 ];
Run Code Online (Sandbox Code Playgroud)

现在,您可以bind通过执行以下操作来提高可读性:

auto target_field_ = phx::bind(&S::target_field, _val);

p = int_ [ target_field_ = _1 ];
Run Code Online (Sandbox Code Playgroud)

概念证明:住在Coliru

#include "boost/spirit/include/qi.hpp"
#include "boost/spirit/include/phoenix.hpp"

namespace qi  = boost::spirit::qi;
namespace phx = boost::phoenix;
typedef std::string::const_iterator It;

struct S
{
    int         field1;
    std::string field2;
    int         target_field;
    bool        field3;
};

int main()
{
    const std::string input("42");
    It f(begin(input)), l(end(input));

    S instance;

    using namespace qi;
    rule<It, S()> p = int_ [ phx::bind(&S::target_field, _val) = _1 ];

    // or, alternatively:
    auto target_field_ = phx::bind(&S::target_field, _val);
    p = int_ [ target_field_ = _1 ];

    if (parse(f, l, p, instance))
        std::cout << "Parsed: " << instance.target_field;
}
Run Code Online (Sandbox Code Playgroud)

选项2(融合序列)

您可以使用自适应将结构视为融合序列:

#include "boost/fusion/adapted/struct.hpp"

BOOST_FUSION_ADAPT_STRUCT(S, (int, field1)(std::string, field2)(int, target_field)(bool, field3))
Run Code Online (Sandbox Code Playgroud)

现在,您可以在语义操作中对这些序列使用phoenix lazy函数:

rule<It, S()> p = int_ [ phx::at_c<2>(_val) = _1 ];
Run Code Online (Sandbox Code Playgroud)

我不喜欢这种风格(因为它'将一种富有表现力的结构'降级为......一种元组),但它可能会派上用场.住在Coliru