Использование boost :: fusion :: map в boost :: spirit :: karma

Я использую Boost Spirit для анализа некоторых текстовых файлов в структуре данных, и теперь я начинаю генерировать текст из этой структуры данных (используя Spirit Karma).

Одной из попыток создания структуры данных является boost :: fusion :: map (как предложено в ответе на
этот вопрос). Но хотя я могу использовать boost :: spirit :: qi :: parse () и легко получать в него данные, когда я пытался сгенерировать из него текст, используя карму, я потерпел неудачу.

Ниже моя попытка (особенно обратите внимание на тип «map_data»). После некоторого чтения и игры с другими типами слияния я обнаружил boost :: fusion :: vector и BOOST_FUSION_DEFINE_ASSOC_STRUCT. Мне удалось сгенерировать выходные данные с ними обоими, но они не кажутся идеальными: в векторе вы не можете получить доступ к члену, используя имя (это похоже на кортеж) — а в другом решении я не думаю, что мне нужно оба способа (имя члена и тип ключа) для доступа к членам.

#include <iostream>
#include <string>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/map.hpp>
#include <boost/fusion/include/make_map.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/transform.hpp>

struct sb_key;
struct id_key;

using boost::fusion::pair;

typedef boost::fusion::map
< pair<sb_key, int>
, pair<id_key, unsigned long>
> map_data;

typedef boost::fusion::vector < int, unsigned long > vector_data;

#include <boost/fusion/include/define_assoc_struct.hpp>
BOOST_FUSION_DEFINE_ASSOC_STRUCT(
(), assocstruct_data,
(int, a, sb_key)
(unsigned long, b, id_key))

namespace karma =  boost::spirit::karma;

template <typename X>
std::string to_string ( const X& data )
{
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
karma::generate_delimited ( sink, karma::int_ << karma::ulong_, karma::space, data );
return generated;
}

int main()
{
map_data d1(boost::fusion::make_map<sb_key, id_key>(234, 35314988526ul));
vector_data d2(boost::fusion::make_vector(234, 35314988526ul));
assocstruct_data d3(234,35314988526ul);

std::cout << "map_data as_vector: " << boost::fusion::as_vector(d1) << std::endl;
//std::cout << "map_data to_string: " << to_string(d1) << std::endl; //*FAIL No 1*
std::cout << "at_key (sb_key): " << boost::fusion::at_key<sb_key>(d1) << boost::fusion::at_c<0>(d1) << std::endl << std::endl;

std::cout << "vector_data: " << d2 << std::endl;
std::cout << "vector_data to_string: " << to_string(d2) << std::endl << std::endl;

std::cout << "assoc_struct as_vector: " << boost::fusion::as_vector(d3) << std::endl;
std::cout << "assoc_struct to_string: " << to_string(d3) << std::endl;
std::cout << "at_key (sb_key): " << boost::fusion::at_key<sb_key>(d3) << d3.a << boost::fusion::at_c<0>(d3) << std::endl;

return 0;
}

Включение закомментированной строки дает много страниц ошибок компиляции, среди которых, в частности, что-то вроде:
неизвестное преобразование для аргумента 1 из «boost :: fusion :: pair» в «double»
неизвестное преобразование для аргумента 1 из «boost :: fusion :: pair» в «float»

Может ли быть так, что to_string нужны значения map_data, а не пары? Хотя я не очень хорошо разбираюсь в шаблонах, я попытался получить вектор с карты с помощью преобразования следующим образом

template <typename P>
struct take_second
{
typename P::second_type operator() (P p)
{
return p.second;
}
};
// ... inside main()
pair <char, int> ff(32);
std::cout << "take_second (expect 32): "<< take_second<pair<char,int>>()(ff) << std::endl;
std::cout << "transform map_data and to_string: "<< to_string(boost::fusion::transform(d1, take_second<>())); //*FAIL No 2*

Но я не знаю, какие типы я должен давать при создании экземпляра take_second, и в любом случае я думаю, что должен быть более простой способ получить (перебрать) значения карты (есть?)

Если вы ответите на этот вопрос, пожалуйста, также выскажите свое мнение о том, лучше ли использовать ASSOC_STRUCT или карту.

3

Решение

Я думаю, что я заметил твой вопрос в списке [общий дух] ранее.

Там было 14 просмотров — и я провел довольно глубокое расследование. К сожалению, насколько мне известно, я не думаю, что у Духа есть какая-либо поддержка ассоциированных структур Fusion.

Фактически, за пределами MSM и Phoenix, не было места в boost, где я вижу использование fusion :: map.

Есть ли шанс, что вы могли бы просто использовать вместо этого std :: map / std :: pair? Вот небольшое доказательство концепции:

#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted.hpp>

int main()
{
const auto data = std::map<std::string, double> {
{ "pi", 3.1415925 },
{ "e", 2.718281828 },
{ "Answer", 42 } };

namespace karma = boost::spirit::karma;
std::cout << karma::format((karma::string << " = " << karma::double_) % karma::eol, data)
<< std::endl;
}

Выход:

Answer = 42.0
e = 2.718
pi = 3.142
3

Другие решения

Других решений пока нет …