Как в библиотеке RapidJSON передать значение JSON массива в vector?
Пишу нейросеть, веса после обучения для неё хотел хранить в файле json. Написал код, с использованием библиотеки RapidJSON. Код компилируется, хоть и с предупреждениями. Функция должна брать значения весов из json массива и передавать их уже в массив(vector) программы
#include "lib/rapidjson/document.h"
#include "lib/rapidjson/writer.h"
#include <vector>
using namespace rapidjson;
void ParseWeights(std::string path, std::vector <double> &weights, int numlayer) {
Document document;
document.Parse(path.c_str());
std::string slayer = "layer" + numlayer;
const Value& layer = document[slayer.c_str()];
assert(layer.IsArray());
for (size_t i = 0; i < layer.Size(); i++)
weights.at(i) = layer[i].GetDouble();
}
Сам json файл выглядит так:
{
"layer1" : [0.2, 0.12, 0.56, 0.58, 0.67, 0.12, 0.12, 0.45, 0.78, 0.55],
"layer2" : [0.3, 0.12, 0.56, 0.348, 0.673, 0.12, 0.12, 0.45, 0.8, 0.1]
}
В итоге при работе функции получаю вот такую ошибку:
main: lib/rapidjson/document.h:1154: rapidjson::GenericValue<Encoding, Allocator>::MemberIterator rapidjson::GenericValue<Encoding, Allocator>::FindMember(const rapidjson::GenericValue<Encoding, SourceAllocator>&) [with SourceAllocator = rapidjson::MemoryPoolAllocator<>; Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; MemberIterator = rapidjson::GenericMemberIterator<false, rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<> >]: Assertion IsObject() failed.
Долго разбирался, копался в документации библиотеки, но так что-либо сделать не смог
Ответы (1 шт):
Во-первых, "layer" + numlayer - это const char* + целое число. "layer" + 1, например, будет указывать на 'a' и приведет к std::string "ayer". Вам нужно использовать std::to_string(numlayer).
Во-вторых, у вас нет элементов в weights поэтому .at(i) всегда будет за пределами. Если вы хотите добавить элементы в std::vector, вы должны использовать push_back.
Я рекомендую вместо этого возвращать std::vector по значению и использовать стандартный алгоритм std::transform для преобразования JSON в std::vector.
Пример получения layer1:
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace rapidjson;
std::vector<double> ParseWeights(std::string path, int numlayer) {
Document document;
document.Parse(path.c_str());
std::string slayer = "layer" + std::to_string(numlayer);
const Value& layer = document[slayer.c_str()];
assert(layer.IsArray());
std::vector<double> weights;
weights.reserve(layer.Size());
std::transform(layer.Begin(), layer.End(), std::back_inserter(weights),
[](const Value& val) { return val.GetDouble(); });
return weights;
// for(SizeType i = 0; i < layer.Size(); i++)
// weights.push_back(layer[i].GetDouble());
}
int main() {
std::string path(R"aw({
"layer1" : [0.2, 0.12, 0.56, 0.58, 0.67, 0.12, 0.12, 0.45, 0.78, 0.55],
"layer2" : [0.3, 0.12, 0.56, 0.348, 0.673, 0.12, 0.12, 0.45, 0.8, 0.1]
})aw");
std::vector<double> weights = ParseWeights(path, 1);
for(double d : weights) std::cout << d << ' ';
std::cout << '\n';
}
Если path — это путь к файлу, то в rapidjson рекомендуется использовать FileReadStream вместе с потоком std::FILE. Это для получения максимальной производительности.
Пример:
#include "rapidjson/document.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/writer.h"
#include <algorithm>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace rapidjson;
auto OpenCStream(const char* path, const char* mode) {
struct FileCloser { // A functor to close a C stream
void operator()(std::FILE* fp) { std::fclose(fp); }
};
std::unique_ptr<std::FILE, FileCloser> ufp(std::fopen(path, mode));
if(not ufp) throw std::runtime_error(std::string("could not open ") + path);
return ufp;
}
Document ReadDocumentFromFile(const std::string& path) {
auto ufp = OpenCStream(path.c_str(), "rb");
char readBuffer[65536];
FileReadStream is(ufp.get(), readBuffer, sizeof readBuffer);
Document document;
document.ParseStream(is);
return document;
}
std::vector<double> ParseWeightsInLayer(const Document& document,
int numlayer) {
std::string slayer = "layer" + std::to_string(numlayer);
const Value& layer = document[slayer.c_str()];
if(not layer.IsArray())
throw std::runtime_error(slayer + " is not an array");
std::vector<double> weights;
weights.reserve(layer.Size());
std::transform(layer.Begin(), layer.End(), std::back_inserter(weights),
[](const Value& val) { return val.GetDouble(); });
return weights;
}
int main() {
auto document = ReadDocumentFromFile("rap.json");
std::vector<double> weights = ParseWeightsInLayer(document, 1);
for(double d : weights) std::cout << d << ' ';
std::cout << '\n';
}