v_map has the correct amount of information stored, however when i try to use std::set it only copies one element ,I assume the first one. This is my first time using std::set , maybe I miss something here...Thanks for your help !
typedef std::map<std::string,std::pair<int,int>> points_map;
void list_average(points_map &v_map)
{
Comparator compFunctor = [](std::pair<std::string,std::pair<int,int>> elem1,std::pair<std::string,std::pair<int,int>> elem2)
{
std::pair<int,int> it = elem1.second;
std::pair<int,int> jt = elem2.second;
return it.first < jt.first;
};
std::set<std::pair<std::string,std::pair<int,int>>,Comparator> v_set(v_map.begin(),v_map.end(),compFunctor);
for (std::pair<std::string,std::pair<int,int>> it : v_set)
{
std::pair<int,int> jt = it.second;
std::cout << it.first << " " << (jt.second - jt.first) / jt.first<< std::endl;
}
}
Note the following is the full program, I apologize in advance for the ugly code , and length of the code ,also I rewrote the name in the upper part of my code, in the full code , this particular function is called list_atlag
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <codecvt>
#include <iterator>
#include <numeric>
#include <functional>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
#include <boost/tokenizer.hpp>
class Adatok
{
public:
Adatok(std::string name, std::string path, std::string date, int points) : _name(name), _path(path), _date(date), _points(points) {}
Adatok(const Adatok &other) = default;
Adatok &operator=(const Adatok &other) = default;
std::string get_name() { return _name; }
std::string get_path() { return _path; }
std::string get_date() { return _date; }
int get_points() { return _points; }
private:
std::string _name;
std::string _path;
std::string _date;
int _points;
};
class Ranglista
{
public:
Ranglista(std::string name, int points) : _name(name), _points(points) {}
Ranglista(const Ranglista &other) = default;
Ranglista &operator=(const Ranglista &other) = default;
std::string get_name() { return _name; }
int get_points() { return _points; }
bool operator<(const Ranglista &other)
{
return _points > other._points;
}
private:
std::string _name;
int _points;
};
class Vedes
{
public:
Vedes(std::string name, int point) : _name(name), _point(point) { _count++; }
Vedes(const Vedes &other) = default;
Vedes &operator=(const Vedes &other) = default;
std::string get_name() { return _name; }
int get_point() { return _point; }
int get_count() { return _count; }
void set_stuff(int &points)
{
_point += points;
_count++;
}
bool operator<(const Vedes &other)
{
return _count > other._count;
}
private:
std::string _name;
int _point;
int _count = 0;
};
typedef std::map<std::string, int> path_value; //minden path + az erteke
typedef std::vector<Adatok> name_path_date; //bejegyzesek
typedef std::vector<Ranglista> ranglista; //ranglista
typedef std::map<std::string,std::pair<int,int>> vedes_vec; //vedesek
typedef std::function<bool(std::pair<std::string,std::pair<int,int>>,std::pair<std::string,std::pair<int,int>>)> Comparator;
void create_pv(path_value &, boost::filesystem::path); //feltolti a path+ertek map-ot
void create_npd(name_path_date &, path_value &, std::string input); //feltolti a bejegyzesek vektorat + mindenki pontszama map
void create_np(name_path_date &, path_value &); // name + path map
void list_np(path_value &name_point); // nam + path kiiratas
void list_bejegyzesek(name_path_date &bejegyzesek); // bejegyzesek vektora kiiratas
bool check_bejegyzesek(name_path_date &bejegyzesek, std::string name, std::string path); //van-e mar ilyen bejegyzes
void create_rl(ranglista &rl_vec, path_value &name_point); //ranglista feltoltes
void list_rl(ranglista &rl_vec); //ranglista kiiratas
void vedes_atlag(name_path_date &bejegyzesek, vedes_vec &v_vec); //vedes atlag map
void list_atlag(vedes_vec &v_vec); //vedes atlag kiiratas
bool check_vedes(vedes_vec &v_vec, std::string name);
void vedes_elem(vedes_vec &v_vec, std::string name, int &&points); //
//void accumulate_pv(path_value&);
int main(int argc, char **argv)
{
std::vector<std::string> roots = {"City/Debrecen/Oktatás/Informatika/Programozás/DEIK/Prog1/", "City/Debrecen/Oktatás/Informatika/Programozás/DEIK/"};
std::string input_file_name = "db-2018-05-06.csv";
/* OPTIONS */
boost::program_options::options_description desc("ALLOWED OPTIONS");
desc.add_options()("help", "help msg")("root,r", boost::program_options::value<std::vector<std::string>>())("csv", boost::program_options::value<std::string>(), "comma separated values")("rank", "rang lista")("vedes", "labor vedesek");
boost::program_options::positional_options_description pdesc;
pdesc.add("root", -1);
boost::program_options::variables_map vm;
boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(desc).positional(pdesc).run(), vm);
boost::program_options::notify(vm);
int sum = 0;
path_value pv_map;
if (vm.count("help") || argc == 1)
{
std::cout << desc << std::endl;
return 1;
}
if (vm.count("root"))
{
roots = vm["root"].as<std::vector<std::string>>();
for (auto &i : roots)
{
boost::filesystem::path path(i);
create_pv(pv_map, path);
}
for (path_value::iterator it{pv_map.begin()}; it != pv_map.end(); it++)
sum += it->second;
//std::cout << sum << std::endl;create_npd
std::cout << std::accumulate(pv_map.begin(), pv_map.end(), 0, [](int value, const std::map<std::string, int>::value_type &p) { return value + p.second; });
std::cout << std::endl;
}
if (vm.count("csv"))
{
//input_file_name = vm["csv"].as<std::string>();
std::ifstream input_file{vm["csv"].as<std::string>()};
name_path_date bejegyzesek;
std::string temp;
path_value name_point;
while (getline(input_file, temp))
create_npd(bejegyzesek, pv_map, temp);
create_np(bejegyzesek, name_point);
//list_bejegyzesek(bejegyzesek);
//list_np(name_point);
if (vm.count("rank"))
{
ranglista rl_vec;
create_rl(rl_vec, name_point);
list_rl(rl_vec);
}
if (vm.count("vedes"))
{
vedes_vec v_vec;
vedes_atlag(bejegyzesek, v_vec);
list_atlag(v_vec);
}
return 0;
}
return 0;
}
void create_pv(path_value &pv_map, boost::filesystem::path path)
{
boost::filesystem::directory_iterator it{path}, eod;
BOOST_FOREACH (boost::filesystem::path const &p, std::make_pair(it, eod))
{
if (boost::filesystem::is_regular_file(p))
{
boost::filesystem::ifstream regular_file{p};
std::string temp;
int sum = 0; //aktualis .props erteke
while (getline(regular_file, temp))
{
temp.erase(0, temp.find_last_of('/'));
temp.erase(0, temp.find_first_of(' '));
sum += std::atoi((temp.substr(temp.find_first_of("0123456789"), temp.find_last_of("0123456789"))).c_str());
}
std::string result = p.string();
std::string result_path = result.substr(0, result.find_last_of('/'));
//std::cout << result_path << std::endl;
//pv_map.insert(std::make_pair(result, sum));
pv_map[result_path] = sum;
}
else
create_pv(pv_map, p);
}
}
//void accumulate_pv(path_value& pv_map)
//{
// std::cout<<std::accumulate(pv_map.begin(),pv_map.end(),0,[](int value,const path_value::int& p){return value+p.second;});
//}
void create_npd(name_path_date &bejegyzesek, path_value &pv_map, std::string input)
{
boost::tokenizer<boost::escaped_list_separator<char>> tokenizer{input};
boost::tokenizer<boost::escaped_list_separator<char>>::iterator it{tokenizer.begin()};
std::string name = *it;
std::string path = *(++it);
std::string date = *(++it);
path = path.substr(2);
if (!check_bejegyzesek(bejegyzesek, name, path))
bejegyzesek.push_back(Adatok(name, path, date, pv_map["/home/erik/Documents/Programs/"+path]));
}
bool check_bejegyzesek(name_path_date &bejegyzesek, std::string name, std::string path)
{
bool ok = false;
for (name_path_date::iterator it{bejegyzesek.begin()}; it != bejegyzesek.end(); it++)
{
if ((it->get_name() == name) && (it->get_path() == path))
ok = true;
}
return ok;
}
bool check_vedes(vedes_vec &v_vec, std::string name)
{
vedes_vec::iterator it = v_vec.find(name);
if (it != v_vec.end()) return true;
else return false;
}
void vedes_elem(vedes_vec &v_vec, std::string name, int &&points)
{
/*for (auto &it : v_vec)
if (it.get_name() == name)
it.set_stuff(points);
*/
vedes_vec::iterator i = v_vec.find(name);
std::pair<int,int> it = i->second;
//auto& jt = it->second;
it.first++;
it.second += points;
}
void create_np(name_path_date &bejegyzesek, path_value &name_point)
{
for (name_path_date::iterator it{bejegyzesek.begin()}; it != bejegyzesek.end(); it++)
if (name_point.count(it->get_name()) == 0)
name_point.insert(std::make_pair(it->get_name(), it->get_points()));
else
name_point[it->get_name()] += it->get_points();
}
void list_np(path_value &name_point)
{
for (path_value::iterator it{name_point.begin()}; it != name_point.end(); it++)
{
if (it->second)
std::cout << it->first << " " << it->second << std::endl;
}
}
void list_bejegyzesek(name_path_date &bejegyzesek)
{
for (name_path_date::iterator it{bejegyzesek.begin()}; it != bejegyzesek.end(); it++)
if (it->get_name() == "Varga Erik")
std::cout << it->get_name() << " " << it->get_path() << " " << it->get_points() << std::endl;
}
void create_rl(ranglista &rl_vec, path_value &name_point)
{
for (auto &it : name_point)
{
if (it.second > 0)
rl_vec.push_back(Ranglista(it.first, it.second));
}
std::sort(rl_vec.begin(), rl_vec.end());
}
void list_rl(ranglista &rl_vec)
{
for (auto &it : rl_vec)
std::cout << it.get_name() << " " << it.get_points() << std::endl;
}
void vedes_atlag(name_path_date &bejegyzesek, vedes_vec &v_vec)
{
std::string key = "City/Debrecen/Oktatás/Informatika/Programozás/DEIK/Prog1/Labor/Védés/";
for (auto &it : bejegyzesek)
{
if ((it.get_path().find("City/Debrecen/Oktatás/Informatika/Programozás/DEIK/Prog1/Labor/Védés/") != std::string::npos) && (it.get_points()) && (!check_vedes(v_vec, it.get_name())))
v_vec.insert(std::make_pair(it.get_name(),std::make_pair(1,it.get_points())));
else if ((check_vedes(v_vec, it.get_name())) && (it.get_path().find("City/Debrecen/Oktatás/Informatika/Programozás/DEIK/Prog1/Labor/Védés/") != std::string::npos) && (it.get_points()))
vedes_elem(v_vec, it.get_name(), it.get_points());
}
}
void list_atlag(vedes_vec &v_vec)
{
//std::sort(v_vec.begin(), v_vec.end());
Comparator compFunctor = [](std::pair<std::string,std::pair<int,int>> elem1,std::pair<std::string,std::pair<int,int>> elem2)
{
std::pair<int,int> it = elem1.second;
std::pair<int,int> jt = elem2.second;
return it.first < jt.first;
};
std::set<std::pair<std::string,std::pair<int,int>>,Comparator> v_set(v_vec.begin(),v_vec.end(),compFunctor);
//int sum = 0;
//int csum = 0;
for (std::pair<std::string,std::pair<int,int>> it : v_set)
{
std::pair<int,int> jt = it.second;
std::cout << it.first << " " << (jt.second - jt.first) / jt.first<< std::endl;
//sum += it.get_point();
//csum += it.get_count();
//sum = std::accumulate(v_vec.begin(), v_vec.end(), 0, [](int i, Vedes &o) { return i + o.get_point(); });
//csum = std::accumulate(v_vec.begin(), v_vec.end(), 0, [](int i, Vedes &o) { return i + o.get_count(); });
}
//std::cout << (sum - csum) / csum << std::endl;
}
so, as described here
template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class set;
std::set is an associative container that contains a sorted set of unique objects of type Key.
I cleaned up your code, and made a Minimal, Complete, and Verifiable example,
#include <iostream>
#include <map>
#include <set>
using point_pair = std::pair<int,int>;
using points_map = std::map<std::string, point_pair>;
using points_set_pair = std::pair<std::string, point_pair>;
auto compFunctor = [](const points_set_pair &elem1, const points_set_pair &elem2)
{
return elem1.second.first < elem2.second.first;
};
using points_set = std::set<points_set_pair, decltype(compFunctor)>;
void list_average(const points_map &v_map)
{
points_set v_set(v_map.begin(),v_map.end(),compFunctor);
for (auto &elem : v_set)
{
const point_pair &jt = elem.second;
std::cout << elem.first << " " << (jt.second - jt.first) / jt.first<< "\n";
}
}
Now consider the first version of main
int main()
{
points_map v_map = { {"foo", { 1, 2}}, {"bar", { 3, 4}}};
list_average(v_map);
}
output:
foo 1
bar 0
Now consider the second version of main:
int main()
{
points_map v_map = { {"foo", { 1, 2}}, {"bar", { 1, 4}}};
list_average(v_map);
}
output:
bar 3
See the problem? As .second.first of the elements are both 1, the latter replaces the first. It is not unique. That's the downside of std::set.
So, what then?
Don't use std::set, but use std::vector and std::sort. Example:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
using point_pair = std::pair<int,int>;
using points_map = std::map<std::string, point_pair>;
using string_point_pair = std::pair<std::string, point_pair>;
auto compFunctor = [](string_point_pair const &elem1, string_point_pair const &elem2)
{
return
elem1.second.first != elem2.second.first?
elem1.second.first < elem2.second.first:
elem1.second.second < elem2.second.second;
};
void list_average(points_map const &v_map)
{
std::vector<string_point_pair> v_vec(v_map.begin(),v_map.end());
std::sort(v_vec.begin(), v_vec.end(), compFunctor);
for (auto &elem : v_vec)
{
const point_pair &jt = elem.second;
std::cout << elem.first << " " << (jt.second - jt.first) / jt.first<< "\n";
}
}
int main()
{
points_map v_map = { {"foo", { 1, 2}}, {"bar", { 1, 4}}, {"baz", { 2, 4}}};
list_average(v_map);
}
Output:
foo 1
bar 3
baz 1
live demo
I was trying this piece of code
demo.hpp
#ifndef DEMO_HPP
#define DEMO_HPP
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <vector>
using namespace std;
typedef boost::function<void(vector<int>)>func;
typedef void (_stdcall *Callback);
class funcPointer
{
public:
void add_call(int, func);
void call_back(int, Callback);
void push_elements();
vector<int> vec;
};
#endif
demo.cpp
#include <iostream>
#include "demo.hpp"
void funcPointer::add_call(int number, func f)
{
cout<<"number: "<<number << endl;
f(vec);
}
void funcPointer::push_elements()
{
vec.push_back(11);
vec.push_back(12);
vec.push_back(13);
}
void funcPointer::call_back(int x, Callback call)
{
cout << "x: " << x <<endl;
}
main.cpp
#include <iostream>
#include "demo.hpp"
void display(vector<int> v)
{
vector<int> ::iterator it;
for(it = v.begin(); it != v.end(); it++)
{
cout<< *it <<endl;
}
}
void Inside_callback()
{
cout << "Hello World" << endl;
}
int main()
{
funcPointer *fun = new funcPointer;
fun->push_elements();
fun->add_call(24, boost::bind(display, _1));
fun->call_back(10, &Inside_callback);
return 0;
}
while compiling I got the following error:
e:\vs_c++\boost_func_ptr\boost_func_ptr\demo.hpp(12): error C2165: 'left-side modifier' : cannot modify pointers to data
I am not able to understand what this error is, and how to get rid of it.
Can somebody help me to get rid of this error??
You have to define type of Callback in following way:
typedef void (_stdcall *Callback)();
You should also modify declaration of Inside_callback in following way for code to compile:
void _stdcall Inside_callback()
I would like to use an unordered_map as a job or session context object. So, I would like to allocate in some function bundle it with a static function in a function object and send this function object to an io_service. And obviously, I do not worry about deallocating it.
Any ideas on how to do that?
Thank you!
#include <iostream>
#include <unordered_map>
#include "boost/asio.hpp"
#include "boost/thread.hpp"
using namespace std;
namespace asio = boost::asio;
typedef std::unique_ptr<asio::io_service::work> work_ptr;
typedef boost::function<void(void) > boost_void_void_fun;
class job_processor {
public:
job_processor(int threads) : thread_count(threads) {
service = new asio::io_service();
work = new work_ptr(new asio::io_service::work(*(service)));
for (int i = 0; i < this->thread_count; ++i)
workers.create_thread(boost::bind(&asio::io_service::run, service));
}
void post_task(boost_void_void_fun job) {
this->service->post(job);
}
void drain() {
this->work->reset();
}
void wait() {
this->workers.join_all();
}
private:
int thread_count;
work_ptr * work;
asio::io_service* service;
boost::thread_group workers;
};
typedef std::unordered_map<string, unsigned long> map_t;
class with_static_function {
public:
static void print_map(map_t map) {
for(map_t::iterator it = map.begin(); it != map.end(); ++it)
std::cout << it->first << ":" << it->second << std::endl;
}
static void print__heap_map(map_t* map) {
if(!map) return;
for(map_t::iterator it = map->begin(); it != map->end(); ++it)
std::cout << it->first << ":" << it->second << std::endl;
}
};
int main(int argc, char** argv) {
map_t words;
words["one"] = 1;
// pass the reference;
with_static_function::print_map(words);
job_processor *pr = new job_processor(4);
{
map_t* heap_map = new map_t;
(*heap_map)["two"] = 2;
// I need this variable to the job_processor;
// and I do not want to worry about deallocation.
// should happen automatically somehow.
// I am ok with changing the variable to be a shared_ptr or
// anything else that works.
boost_void_void_fun fun = boost::bind(
&with_static_function::print__heap_map,
heap_map);
fun(); // if binding was done right this should have worked.
pr->post_task(fun);
}
pr->drain();
pr->wait();
delete pr;
return 0;
}
A number of observations:
Stop Emulating Java. Do not use new unless you're implementing an ownership primitive (smart handle/pointer type). Specifically, just create a pr:
job_processor pr(4);
Same goes for all the members of job_processor (you were leaking everything, and if job_processor were copied, you'd get double-free Undefined Behaviour
The code
// pass the reference;
with_static_function::print_map(words);
passes by value... meaning the whole map is copied
to avoid that copy, fix the print_map signature:
static void print_map(map_t const& map) {
for(map_t::const_iterator it = map.begin(); it != map.end(); ++it)
std::cout << it->first << ":" << it->second << std::endl;
}
Of course, consider just writing
static void print_map(map_t const& map) {
for(auto& e : map)
std::cout << e.first << ":" << e.second << "\n";
}
The "heap" overload of that could be, as my wording implies, an overload. Be sure to remove the useless duplication of code (!):
static void print_map(map_t const* map) {
if (map) print_map(*map);
}
You don't even need that overload because you can simply use a lambda to bind (instead of boost::bind):
auto heap_map = boost::make_shared<map_t>();
heap_map->insert({{"two", 2}, {"three", 3}});
boost_void_void_fun fun = [heap_map] { with_static_function::print_map(*heap_map); };
Complete working program:
Live On Coliru
#include <iostream>
#include <unordered_map>
#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
namespace asio = boost::asio;
typedef boost::function<void(void)> boost_void_void_fun;
class job_processor {
public:
job_processor(int threads) : service(), work(boost::asio::io_service::work(service))
{
for (int i = 0; i < threads; ++i)
workers.create_thread(boost::bind(&asio::io_service::run, &service));
}
void post_task(boost_void_void_fun job) {
service.post(job);
}
void drain() {
work.reset();
}
void wait() {
workers.join_all();
}
private:
asio::io_service service;
boost::optional<asio::io_service::work> work;
boost::thread_group workers;
};
typedef std::unordered_map<std::string, unsigned long> map_t;
namespace with_static_function {
static void print_map(map_t const& map) {
for(auto& e : map)
std::cout << e.first << ":" << e.second << "\n";
}
}
int main() {
// pass the reference;
with_static_function::print_map({ { "one", 1 } });
job_processor pr(4);
{
auto heap_map = boost::make_shared<map_t>();
heap_map->insert({{"two", 2}, {"three", 3}});
boost_void_void_fun fun = [heap_map] { with_static_function::print_map(*heap_map); };
pr.post_task(fun);
}
pr.drain();
pr.wait();
}
Prints
one:1
three:3
two:2
I get a queue of events which must contain a class with generic variables. In order to do that I tried to use the tuples. I used variadic templates to generate my tuples but I can't put them in my queue because of their types which aren't the same. Could you give me some advise about how to do this?
#include <type_traits>
#include <iostream>
#include <vector>
#include <iostream>
#include <tuple>
#include <utility>
#include <queue>
class Logs
{
public:
Logs() {}
template <class T, class... Values>
void write(T data, Values&&... values) {
auto save = std::tuple_cat(_t, std::make_tuple(data)); // I would like to save the return in a variable class
write(values...);
}
void write() {
// the end
// _queue.push(save);
}
std::tuple& getTuple() { return _t;}
private:
std::tuple<> _t;
std::queue<std::tuple<>> _queue;
};
#include <iostream>
int main(int ac, char **av) {
Logs log;
Logs log2;
log.write(4, "42");
log.write(Logs(), 4.5f, 42, "toto");
log.write({"hello", "titi"}, 84, "foo");
// std::cout << std::get<0>(log.getTuple()) << std::endl;
return 0;
}
Which could be the type of _t and _queue ?
I would like to push in my queue get one time a std::tuple<int, std::string, Log. float, ...> then a std::tuple<std::vector<std::string>, int, long>, etc. .
You could use a union as the type of your std::queue, like this:
#include <iostream>
#include <queue>
typedef union Data {
int i;
float f;
char str[20];
struct foo {
int a;
char c;
} foo;
struct bar {
int a;
double d;
} bar;
} data;
int main () {
std::queue<data> q;
data mydata;
mydata.i = 5;
q.push(mydata);
data mydata1;
mydata1.f = 3.14;
q.push(mydata1);
data mydata2;
strcpy(mydata2.str, "foo");
q.push(mydata2);
data mydata3;
mydata3.foo.a = 1;
mydata3.foo.c = 'a';
q.push(mydata3);
data mydata4;
mydata4.bar.a = 7;
mydata4.bar.d = 2.78;
q.push(mydata4);
int i = 0;
while(!q.empty()) {
if(i == 0) {
std::cout << ' ' << q.front().i;
} else if(i == 1) {
std::cout << ' ' << q.front().f;
} else if(i == 2) {
std::cout << ' ' << q.front().str;
} else if(i == 3) {
std::cout << ' ' << q.front().foo.a << " " << q.front().foo.c;
} else if(i == 4) {
std::cout << ' ' << q.front().bar.a << " " << q.front().bar.d;
} else {
std::cout << "I do not know what the item has\n";
}
q.pop();
++i;
}
return 0;
}
However, consider that you can not easily use an std::string for example inside a union, either a std::tuple, thus you have to re-think if you can give a shot for the boost::variant, because as you see the code is becoming easily non-maintainable.
In an ItemList containing lists of Item objects, how do I access the Item objects in the generator?
The following sample code compiles on VC9 (with boost include and link directories set apropriately).
I don't know how to set up list_generator::item.
#include <boost/config/warning_disable.hpp>
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iostream>
#include <string>
#include <list>
namespace karma = boost::spirit::karma;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
class Item
{
public:
typedef std::vector<int> Values;
Item(const std::string & i, const Values & v) : m_id(i), m_values(v) {}
std::string getId() const { return m_id; }
const Values & getValues() const { return m_values; }
private:
std::string m_id;
Values m_values;
};
class ItemList
{
public:
typedef std::map<std::string, Item> Items;
ItemList() {}
ItemList(const Items & s, const Items & o) : m_some(s), m_other(o) {}
const Items getSome() const { return m_some; }
const Items getOther() const { return m_other; }
private:
Items m_some;;
Items m_other;
};
template <typename Iterator>
struct list_generator : karma::grammar<Iterator, ItemList()>
{
list_generator(const ItemList & i) : list_generator::base_type(start)
{
using karma::int_;
using karma::_1;
using karma::lit;
// Convert maps into lists containing only the values
typedef std::vector<Item> Cells;
const Cells some = boost::copy_range<Cells>(i.getSome() | boost::adaptors::map_values);
const Cells other = boost::copy_range<Cells>(i.getOther() | boost::adaptors::map_values);
item =
lit("<item>")
<< lit("<id>") /*<< lit[_1 = ??.getId()]*/ << lit("</id>") // Item ID
<< lit("<values>") /*<< (int_ % ';')[_1 = ??.getValues()]*/ << lit("</values>") // List of Item values
<< lit("</item>");
start =
lit("<some>") << (*item)[_1 = some] << lit("</some>")
<< lit("<other>") << (*item)[_1 = other] << lit("</other>");
}
karma::rule<Iterator, Item()> item;
karma::rule<Iterator, ItemList()> start;
};
int main()
{
const Item::Values values = boost::assign::list_of(1)(2)(3);
const Item a("a", values);
const Item b("b", values);
ItemList::Items some, other;
some.insert(std::make_pair(a.getId(), a));
other.insert(std::make_pair(b.getId(), b));
const ItemList items(some, other);
typedef std::back_insert_iterator<std::string> Iter;
typedef list_generator<Iter> Generator;
Generator grammar(items);
std::string generated;
Iter sink(generated);
if (!karma::generate(sink, grammar))
{
std::cout << "Generating failed\n";
}
else
{
std::cout << "Generated: " << generated << "\n";
}
return 0;
}
The output is:
Generated: <some><item><id></id><values></values></item></some><other><item><id></id><values></values></item></other>
You should use karma::_val. For example you can write some binders (simple example)
<< lit("<id>")
<< karma::string[_1 = phoenix::bind(&Item::getId, karma::_val)]
<< lit("</id>") // Item ID
<< lit("<values>")
<< (int_ % ';')[_1 = phoenix::bind(&Item::getValues, karma::_val)]
<< lit("</values>") // List of Item values