w3hello.com logo
Home PHP C# C++ Android Java Javascript Python IOS SQL HTML videos Categories
Boost Spirit Qi Custom Syntesized Attribute (Set a specific member of a struct attribute via a semantic action)

How to set a struct member.

Option 1 (phx::bind)

Given a struct S

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

You can assign to a field (e.g. target_field) like so:

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

Now, you can make the bind more readable, by doing something like:

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

p = int_ [ target_field_ = _1 ];

Proof of concept: live on 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;
}

Option 2 (fusion sequences)

You can treat a struct as a fusion sequence by using adaptation:

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

BOOST_FUSION_ADAPT_STRUCT(S, (int, field1)(std::string, field2)(int,
target_field)(bool, field3))

Now you can use phoenix lazy functions on these sequences in your semantic action:

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

I don't prefer this style (because it 'degrades' an expressive struct to ... a tuple of sorts), but it might come in handy. Live on Coliru





© Copyright 2018 w3hello.com Publishing Limited. All rights reserved.