3

Say if I have a simple struct like:

struct huh { char xxx; };  

Without going to Boost Fusion adapted structs, I'd like to find a simpler proxy for operating on a member variable for in a Spirit rule's semantic action. Now this, of course, doesn't work:

_val.xxx = _1

but I'd like to get a little cleaner than binding with phoenix:

bind(&huh::xxx, _val) =  _1 

Here is a working example of the simple picture that compiles on a clang and a g++:

#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/phoenix/bind/bind_member_variable.hpp>

struct huh { char xxx; };

int main() {
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    namespace phx   = boost::phoenix;

    qi::rule<std::string::const_iterator, huh(), ascii::space_type> start;

    start =  qi::char_[
        phx::bind(&huh::xxx, qi::_val) =  qi::_1 
    ];

    return 0;
}

Any ideas?

Matt Hurd
  • 125
  • 7
  • [This](http://stackoverflow.com/a/22426069/2417774) is something silly I tried some time ago. With it you can use something like [`qi::char_[my_val.xxx=qi::_1]`](http://coliru.stacked-crooked.com/a/a17a8670595d0dce). You'll need to use an adapting macro so if that was your problem this solution won't help. – llonesmiz Aug 29 '15 at 10:44

1 Answers1

2

Binding with fusion is exactly the glue to make it "a little cleaner than binding with phoenix".

So, there's your solution. Alternatively, factor your expression templates, maybe:

auto _xxx = phx::bind(&huh::xxx, _val);

So you can write:

start =  char_[ _xxx = _1 ];

Alternatively, use a function or a customization point:

Customization point

Adding a trait

namespace boost { namespace spirit { namespace traits {

    template <> struct assign_to_attribute_from_value<huh, char, void> {
        static void call(char c, huh& attr) { attr.xxx = c; }
    };

} } }

You can now simply write

qi::rule<std::string::const_iterator, huh(), ascii::space_type> start;

start = qi::char_;

Live On Coliru

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>

struct huh { char xxx; };

namespace boost { namespace spirit { namespace traits {

    template <> struct assign_to_attribute_from_value<huh, char, void> {
        static void call(char c, huh& attr) { attr.xxx = c; }
    };

} } }

int main() {
    namespace qi    = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    qi::rule<std::string::const_iterator, huh(), ascii::space_type> start;

    start = qi::char_;
}
Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Added the customization point example [Live On Coliru](http://coliru.stacked-crooked.com/a/19023b1e921c2cea) – sehe Aug 29 '15 at 10:56
  • The customization point approach is better, and probably faster, but it's so ugly :p. It's a shame there isn't a macro or something to make it simpler to write. – llonesmiz Aug 29 '15 at 11:02
  • There is, and I'd claim it's called `BOOST_FUSION_ADAPT_STRUCT`. In many ways – sehe Aug 29 '15 at 11:06
  • Can I tempt you to look at something that I think would be pretty cool (if it were done by a better programmer)?. It's in the [comment above](http://stackoverflow.com/questions/32284424/boost-spirit-semantic-actions-on-non-fusion-adapted-structs#comment52448066_32284424). If you decide to look at it skip (the really messy part) to the end to see how it is used (the cool part). – llonesmiz Aug 29 '15 at 12:07
  • @cv_and_he Yeah, that would be cool, though I'd personally think that the effort required is not proportional (I'd pick the `auto val_xxx = phx::bind(&huh::xxx, _val);` shown in my answer). If we want to have this, we should base it on future language reflection support. $0.02 – sehe Aug 29 '15 at 12:13
  • Thanks for all of this, especially as a stackoverflow user for the very first time. I'd have to agree that `BOOST_FUSION_ADAPT_STRUCT` is perhaps the right answer if that could work. The issue here is dealing with external & old code. Also calling a member function, say `push_back`, on an exposed `std::vector` escapes the Fusion domain. My solution has been to write a parser to extract and make Fusion adaptions for the approx 300 structs :-) The `auto _xxx` is especially useful for those more complex binds though. Thanks all. – Matt Hurd Aug 30 '15 at 02:47