Позвольте мне сначала объяснить, почему хлопья выводят более подробный стиль, чем вам хотелось бы. хлопья написаны для работы с произвольными архивами сериализации и используют золотую середину для удовлетворения всех из них. Представьте себе, что тип ключа — это нечто гораздо более сложное, чем строковый или арифметический тип — как мы можем сериализовать его простым "key" : "value"
способом?
Также обратите внимание, что злаки должны быть прародителями любых данных, которые они считывают.
При этом то, что вы хотите, вполне возможно с хлопьями, но есть несколько препятствий:
Самым большим препятствием, которое необходимо преодолеть, является тот факт, что желаемый ввод сериализует некоторое неизвестное количество пар имя-значение внутри объекта JSON, а не массива JSON. хлопья были разработаны для использования массивов JSON при работе с контейнерами, которые могут содержать переменное количество элементов, поскольку это имело наибольший смысл с учетом используемого базового синтаксического анализатора rapidjson.
Во-вторых, хлопья в настоящее время не ожидают, что имя в паре имя-значение будет фактически загружено в память — оно просто использует их как организационный инструмент.
Таким образом, вот полностью работающее решение (можно сделать более элегантным) вашей проблемы с минимальными изменениями в хлопьях (на самом деле это изменение, которое для хлопьев 1.1, текущая версия 1.0):
Добавьте эту функцию в JSONInputArchive
:
//! Retrieves the current node name
/*! @return nullptr if no name exists */
const char * getNodeName() const
{
return itsIteratorStack.back().name();
}
Затем вы можете написать специализацию сериализации для std::map
(или неупорядоченной, в зависимости от того, что вы предпочитаете) для пары строк. Обязательно поместите это в пространство имен cereal
, чтобы его мог найти компилятор. Этот код должен существовать где-то в ваших собственных файлах:
namespace cereal
{
//! Saving for std::map<std::string, std::string>
template <class Archive, class C, class A> inline
void save( Archive & ar, std::map<std::string, std::string, C, A> const & map )
{
for( const auto & i : map )
ar( cereal::make_nvp( i.first, i.second ) );
}
//! Loading for std::map<std::string, std::string>
template <class Archive, class C, class A> inline
void load( Archive & ar, std::map<std::string, std::string, C, A> & map )
{
map.clear();
auto hint = map.begin();
while( true )
{
const auto namePtr = ar.getNodeName();
if( !namePtr )
break;
std::string key = namePtr;
std::string value; ar( value );
hint = map.emplace_hint( hint, std::move( key ), std::move( value ) );
}
}
} // namespace cereal
Это не самое элегантное решение, но оно работает хорошо. Я оставил все в общем шаблоне, но то, что я написал выше, будет работать только с архивами JSON с учетом внесенных изменений. Добавление аналогичного getNodeName()
в XML-архив, вероятно, позволит ему работать и там, но очевидно, что это не имеет смысла для двоичных архивов.
Чтобы сделать это чистым, вы должны поставить enable_if
вокруг этого для архивов, с которыми он работает. Вам также потребуется изменить архивы JSON в хлопьях для работы с объектами JSON переменного размера. Чтобы получить представление о том, как это сделать, посмотрите, как злаки устанавливают состояние в архиве, когда получают SizeTag
для сериализации. По сути, вам нужно сделать так, чтобы архив не открывал массив, а вместо этого открывал объект, а затем создавал свою собственную версию loadSize()
, которая бы видела, насколько велик объект (это будет Member
на языке Rapidjson).
Чтобы увидеть вышеописанное в действии, запустите этот код:
int main()
{
std::stringstream ss;
{
cereal::JSONOutputArchive ar(ss);
std::map<std::string, std::string> filter = {{"type", "sensor"}, {"status", "critical"}};
ar( CEREAL_NVP(filter) );
}
std::cout << ss.str() << std::endl;
{
cereal::JSONInputArchive ar(ss);
cereal::JSONOutputArchive ar2(std::cout);
std::map<std::string, std::string> filter;
ar( CEREAL_NVP(filter) );
ar2( CEREAL_NVP(filter) );
}
std::cout << std::endl;
return 0;
}
и вы получите:
{
"filter": {
"status": "critical",
"type": "sensor"
}
}
{
"filter": {
"status": "critical",
"type": "sensor"
}
}
person
Azoth
schedule
23.03.2014