Boost karma - generate multiple lines from one attribute
I am using a karma genator that absorbs a vector of pairs - simulative to http://boost-spirit.com/home/articles/karma-examples/output-generation-from-a-list-of-key-value-pairs-using -spirit-karma /
I built an example to show my problem after the article above
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/include/karma.hpp>
namespace karma = boost::spirit::karma;
typedef std::pair<std::string, std::string > pair_type;
template <typename OutputIterator>
struct keys_and_values : karma::grammar<OutputIterator, std::vector<pair_type>()>
{
keys_and_values() : keys_and_values::base_type(query)
{
query = *pair;
// here is the interesting part
pair = karma::string << ' ' << karma::string << ' ' << karma::string << karma::eol;
}
karma::rule<OutputIterator, std::vector<pair_type>()> query;
karma::rule<OutputIterator, pair_type()> pair;
};
int main(int argc, char *argv[])
{
typedef std::back_insert_iterator<std::string> sink_type;
std::vector<pair_type> v;
v.push_back(pair_type("key1", "value1"));
v.push_back(pair_type("key2", "value2"));
v.push_back(pair_type("key3", "value3"));
std::string generated;
sink_type sink(generated);
keys_and_values<sink_type> g;
bool result = karma::generate(sink, g, v);
std::cout << generated << std::endl;
return 0;
}
What I am trying to achieve is a result like "value1 key1 value1" . It usually prints out "key1 value1" (but only if you remove the third line karma :: in my example) I've already tried a lot of things with semantic actions, for example.
pair = karma::string[karma::_1 = karma::_val] ...
However, this doesn't work. I probably need something else to get the value from my std :: pair.
These 2 questions looked interesting but didn't solve my problem to reuse the parsed variable with boost karma How to access nested object data in boost :: spirit :: karma?
source to share
While it would technically seem like a natural match here, I would probably resort to using a local address: karma::duplicate[]
Update: As the commenter pointed out, I was reading and changing the key / value incorrectly. Here BOOT_FUSION_ADAPT_STRUCT_NAMED would look ok!
BOOST_FUSION_ADAPT_STRUCT_NAMED(
pair_type const, pair_as_vkv,
(std::string, second)
(std::string, first)
(std::string, second)
)
And now you can just write
template <typename OutputIterator>
struct keys_and_values : karma::grammar<OutputIterator, std::vector<pair_type>()>
{
keys_and_values() : keys_and_values::base_type(query)
{
query = *pair;
pair = karma::string << ' ' << karma::string << ' ' << karma::string << karma::eol;
}
karma::rule<OutputIterator, std::vector<pair_type>()> query;
karma::rule<OutputIterator, boost::fusion::adapted::pair_as_vkv()> pair;
};
Without further ado: see Live On Coliru
Output
value1 key1 value1
value2 key2 value2
value3 key3 value3
Full list
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/karma.hpp>
typedef std::pair<std::string, std::string> pair_type;
BOOST_FUSION_ADAPT_STRUCT_NAMED(
pair_type const, pair_as_vkv,
(std::string, second)
(std::string, first)
(std::string, second)
)
namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;
template <typename OutputIterator>
struct keys_and_values : karma::grammar<OutputIterator, std::vector<pair_type>()>
{
keys_and_values() : keys_and_values::base_type(query)
{
query = *pair;
pair = karma::string << ' ' << karma::string << ' ' << karma::string << karma::eol;
}
karma::rule<OutputIterator, std::vector<pair_type>()> query;
karma::rule<OutputIterator, boost::fusion::adapted::pair_as_vkv()> pair;
};
int main(int argc, char *argv[])
{
typedef std::back_insert_iterator<std::string> sink_type;
std::vector<pair_type> v;
v.push_back(pair_type("key1", "value1"));
v.push_back(pair_type("key2", "value2"));
v.push_back(pair_type("key3", "value3"));
std::string generated;
sink_type sink(generated);
keys_and_values<sink_type> g;
karma::generate(sink, g, v);
std::cout << generated << std::endl;
return 0;
}
source to share