3 votes

Pourquoi est-ce que je reçois l'erreur "échec de l'assertion interne de rapidjson : IsArray()"?

Donc je voulais écrire le code pour mon mini jeu et besoin de lire un fichier json pour la configuration du joueur. Pour cela, j'ai utilisé la bibliothèque cereal.

Mon code m'a donné une erreur, donc je l'ai réduit à un exemple plus simple mais j'ai toujours eu une erreur.

Mon code :

#include <cereal/types/map.hpp>
#include <cereal/types/string.hpp>
#include <cereal/archives/json.hpp>
#include <string>
#include <map>
#include <iostream>
#include <fstream>

struct Item {
    std::string name;
    int number;

    template <class Archive>
    void serialize(Archive &ar) {
        ar(cereal::make_nvp("name", name), cereal::make_nvp("number", number));
    }
};

int main() {
    std::map<std::string, Item> items;
    std::ifstream file("dataForTesting.json");
    if (!file.is_open()) {
        std::cerr << "Impossible d'ouvrir le fichier !" << std::endl;
        return 1;
    }

    try {
        cereal::JSONInputArchive archive(file);
        archive(items);
    } catch (const cereal::Exception& e) {
        std::cerr << "Erreur lors de la désérialisation du JSON : " << e.what() << std::endl;
        return 1;
    } catch (const std::exception& e) {
        std::cerr << "Une erreur s'est produite : " << e.what() << std::endl;
        return 1;
    }

    for (const auto& item : items) {
        std::cout << "ID de l'item : " << item.first 
                  << "\nNom : " << item.second.name 
                  << "\nNombre : " << item.second.number << "\n" << std::endl;
    }
    return 0;
}

Mon fichier json :

{
    "item1": {
        "name": "Objet Un",
        "number": 1
    },
    "item2": {
        "name": "Objet Deux",
        "number": 2
    },
    "item3": {
        "name": "Objet Trois",
        "number": 3
    }
}

J'ai compilé via $ c++ testingTesting.c++ -o test -std=c++11 -I. et exécuté via $ ./test et voici une erreur que j'ai obtenue Erreur lors de la désérialisation du JSON: échec de l'assertion interne de rapidjson : IsArray()

3voto

Marek R Points 4503

Fondamentalement, vous devriez consulter la documentation de cereal! Il explique comment std::map est archivé :

cereal Docs - Spécialisation d'archives

Sortie en utilisant le support intégré de cereal :

{
  "filter": [
    { "key": "type", "value": "sensor" },
    { "key": "status", "value": "critical" }
  ]
}

Remarquez qu'il archive les données en spécifiant explicitement "key" et "value". La raison est que la clé pour std::map n'a pas besoin d'être une std::string, elle peut être n'importe quoi et elle doit également être sérialisée. Notez que en JSon la clé doit être une chaîne de caractères.

Donc en utilisant le support intégré par défaut pour std::map vous devez ajuster votre JSon :

{
    "values": [
        {
            "key": "item1",
            "value": {
                "name": "Item One",
                "number": 1
            }
        },
        {
            "key": "item2",
            "value": {
                "name": "Item Two",
                "number": 2
            }
        },
        {
            "key": "item3",
            "value": {
                "name": "Item Three",
                "number": 3
            }
        }
    ]
}

Ensuite, cela fonctionne.

Alternativement, la documentation propose un exemple de modification de ce comportement. Voir la section "Spécialisation du type".

Voici ma tentative d'utiliser cette approche :

#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct Item {
    std::string name;
    int number;

    template 
    void serialize(Archive& ar)
    {
        ar(cereal::make_nvp("name", name), cereal::make_nvp("number", number));
    }
};

//! Chargement pour std::map pour les archives basées sur le texte
template ::value> = cereal::traits::sfinae>
inline void cereal::load(Archive& ar, std::map& map)
{
    map.clear();

    auto hint = map.begin();
    while (true) {
        const auto namePtr = ar.getNodeName();
        if (!namePtr)
            break;
        std::string key = namePtr;
        Item value;
        ar(value);
        hint = map.emplace_hint(hint, std::move(key), std::move(value));
    }
}

int main()
try {
    std::map items;

    cereal::JSONInputArchive archive(std::cin);
    archive(cereal::make_nvp("values", items));

    for (const auto& item : items) {
        std::cout << "ID de l'élément : " << item.first
                  << "\nNom : " << item.second.name
                  << "\nNombre : " << item.second.number << "\n"
                  << std::endl;
    }
    return 0;
} catch (const cereal::Exception& e) {
    std::cerr << "Erreur lors de la désérialisation de JSON : " << e.what() << std::endl;
    return 1;
} catch (const std::exception& e) {
    std::cerr << "Une erreur est survenue : " << e.what() << std::endl;
    return 1;
}

Il y a toujours un niveau supplémentaire dans JSon, mais je vous laisse ajuster cela.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X