Search code examples
c++boostboost-spirit

Boost Karma, reordering struct elements


Say I have a struct like so:

struct MyStruct
{
    int a;
    int b; 
    int c;
}

BOOST_FUSION_ADAPT_STRUCT
(
    MyStruct,
    (int, a)
    (int, b)
    (int, c)
)

And then if I have a simple generator:

struct MyStructGenerator
    : boost::spirit::karma::grammar<boost::spirit::ostream_iterator, MyStruct()>
{
    MyStructGenerator() : MyStructGenerator::base_type(start_)
    {

        namespace bsk = boost::spirit::karma;

        start_ = '<' 
            << bsk::int_
            << ','
            << bsk::int_
            << ','
            << bsk::int_
            << '>';
    }

    ~MyStructGenerator() = default;
    boost::spirit::karma::rule<boost::spirit::ostream_iterator, MyStruct()> start_;
};

And I run the following:

int main()
{
    MyStruct ms = { 3, 2, 1 };
    std::cout << boost::spirit::karma::format(MyStructGenerator(), ms) << std::endl;
}

I, of course, expect to see <3, 2, 1>. What I cannot figure out is how to change the order within the rule? What if I wanted to see <1, 2, 3> or even if I wanted to see <2, 1, 3>?

Also, is there anyway I could do this without BOOST_FUSION_ADAPT_STRUCT?


Solution

  • You could simply use phoenix and bind to access the member values. So for your example to swap the member it would be like this:

    #include <iostream>
    #include <boost/spirit/include/karma.hpp>
    #include <boost/spirit/include/phoenix_core.hpp>
    #include <boost/spirit/include/phoenix_operator.hpp>
    #include <boost/phoenix/bind/bind_member_variable.hpp>
    using namespace std;
    struct MyStruct {
        int a;
        int b; 
        int c;
    };
    
    struct MyStructGenerator : boost::spirit::karma::grammar<boost::spirit::ostream_iterator, MyStruct()>
    {
        MyStructGenerator() : MyStructGenerator::base_type(start_)
        {
            namespace bsk = boost::spirit::karma;
            start_ = '<' 
                << bsk::int_[bsk::_1 = boost::phoenix::bind(&MyStruct::c, bsk::_val)]
                << ','
                << bsk::int_[bsk::_1 = boost::phoenix::bind(&MyStruct::b, bsk::_val)]
                << ','
                << bsk::int_[bsk::_1 = boost::phoenix::bind(&MyStruct::a, bsk::_val)]
                << '>';
        }
    
        ~MyStructGenerator() = default;
        boost::spirit::karma::rule<boost::spirit::ostream_iterator, MyStruct()> start_;
    };
    
    int main() {
        MyStruct ms = { 3, 2, 1 };
        std::cout << boost::spirit::karma::format(MyStructGenerator(), ms) << std::endl;
    }