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?
<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>.
Well. I can show you a couple of things that might interest you:
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>
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>
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With