Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 767
Addy Avatar asked Jan 18 '26 10:01

Addy


1 Answers

Q1 What if I wanted to see <1, 2, 3> or even if I wanted to see <2, 1, 3>

Just change the adapted order:

Simplified Live On Wandbox:

#include <boost/fusion/adapted/struct.hpp>

struct MyStruct { int a, b, c; };
BOOST_FUSION_ADAPT_STRUCT(MyStruct, a, b, c)

#include <boost/spirit/include/karma.hpp>
namespace bsk = boost::spirit::karma;

template <typename It = boost::spirit::ostream_iterator>
struct MyGen : bsk::grammar<It, MyStruct()> {
    MyGen() : MyGen::base_type(start_) {
        using namespace bsk;
        start_ = '<' << int_ << ',' << int_ << ',' << int_ << '>';
    }
  private:
    bsk::rule<It, MyStruct()> start_;
};

int main() {
    MyGen<> gen;
    std::cout << format(gen, MyStruct { 3, 2, 1 }) << "\n";
}

Prints <3,2,1>, but with

BOOST_FUSION_ADAPT_STRUCT(MyStruct, c, b, a)

Prints <1,2,3>.

Q2 Without Adapting?

Well. I can show you a couple of things that might interest you:

  1. without Karma: Live On Wandbox:

    #include <boost/fusion/adapted/struct.hpp>
    
    struct MyStruct { int a, b, c; };
    BOOST_FUSION_ADAPT_STRUCT(MyStruct, c, b, a)
    
    #include <iostream>
    #include <boost/fusion/include/io.hpp>
    #include <boost/fusion/include/as_vector.hpp>
    using boost::fusion::as_vector;
    
    int main() {
        MyStruct ms { 3, 2, 1 };
        std::cout << as_vector(ms) << "\n";
    
        std::cout 
            << boost::fusion::tuple_open("<")
            << boost::fusion::tuple_delimiter(",")
            << boost::fusion::tuple_close(">");
    
        std::cout << as_vector(ms) << "\n";
    }
    

    Prints

    (1 2 3)
    <1,2,3>
    
  2. Named adaptations: you can adapt different orders at the same time by using the *_NAMED macros. Here's a demo that shows it both using Fusion IO and the Karma generator.

    Note I slightly modified the struct so it's easier to track which field is 'a', 'b' or 'c'.

    See it Live On Wandbox:

    #include <boost/fusion/adapted/struct.hpp>
    
    struct MyStruct { char a, b, c; };
    BOOST_FUSION_ADAPT_STRUCT_NAMED(MyStruct, AsABC, a, b, c)
    BOOST_FUSION_ADAPT_STRUCT_NAMED(MyStruct, AsBCA, b, c, a)
    BOOST_FUSION_ADAPT_STRUCT_NAMED(MyStruct, AsCBA, c, b, a)
    
    #include <boost/spirit/include/karma.hpp>
    #include <boost/spirit/include/qi.hpp>
    namespace bsk = boost::spirit::karma;
    
    template <typename Attr, typename It = boost::spirit::ostream_iterator>
    struct MyGen : bsk::grammar<It, Attr()> {
        MyGen() : MyGen::base_type(start_) {
            using namespace bsk;
            start_ = '<' << auto_ << ',' << auto_ << ',' << auto_ << '>';
        }
      private:
        bsk::rule<It, Attr()> start_;
    };
    
    #include <iostream>
    #include <boost/fusion/include/io.hpp>
    #include <boost/fusion/include/as_vector.hpp>
    using boost::fusion::as_vector;
    
    template <typename Attr>
    void do_tests(Attr const& ms) {
        std::cout << as_vector(ms) << "\n";
        std::cout << format(MyGen<Attr>{}, ms) << "\n";
    }
    
    int main() {
        std::cout << boost::fusion::tuple_open("<") << boost::fusion::tuple_delimiter(",") << boost::fusion::tuple_close(">");
    
        MyStruct ms { 'a', 'b', 'c' };
    
        using namespace boost::fusion::adapted;
        do_tests(AsABC{ms});
        do_tests(AsCBA{ms});
        do_tests(AsBCA{ms});
    }
    

    Prints

    <a,b,c>
    <a,b,c>
    <c,b,a>
    <c,b,a>
    <b,c,a>
    <b,c,a>
    
  3. Yes you can do without adapting (don't though):

    Live On Wandbox (commenting parts because of compiletime limitations)

    struct MyStruct { char a, b, c; };
    
    #include <boost/spirit/include/karma.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    namespace bsk = boost::spirit::karma;
    namespace phx = boost::phoenix;
    
    template <typename It = boost::spirit::ostream_iterator>
    struct MyGen : bsk::grammar<It, MyStruct()> {
        MyGen() : MyGen::base_type(start_) {
            using boost::proto::deep_copy;
            using namespace bsk;
            auto A = deep_copy(char_[ _1 = phx::bind(&MyStruct::a, _val) ]);
            auto B = deep_copy(char_[ _1 = phx::bind(&MyStruct::b, _val) ]);
            auto C = deep_copy(char_[ _1 = phx::bind(&MyStruct::c, _val) ]);
            start_ =
                '<' << A << ',' << B << ',' << C << '>' << eol <<
                '<' << A << ',' << C << ',' << B << '>' << eol <<
                '<' << B << ',' << A << ',' << C << '>' << eol <<
                '<' << C << ',' << A << ',' << B << '>' << eol <<
                '<' << B << ',' << C << ',' << A << '>' << eol <<
                '<' << C << ',' << B << ',' << A << '>' << eol
                ;
        }
      private:
        bsk::rule<It, MyStruct()> start_;
    };
    
    int main() {
        std::cout << format(MyGen<>{}, MyStruct { 'a', 'b', 'c' });
    }
    

    Prints

    <a,b,c>
    <a,c,b>
    <b,a,c>
    <c,a,b>
    <b,c,a>
    <c,b,a>
    
like image 85
sehe Avatar answered Jan 20 '26 01:01

sehe



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!