6
votes

Comment concevoir une classe sérialisable de sorte que tout attribut non sérialisé conduit à une erreur de compilation?

Dites que vous avez le code suivant:

class A {
  bool _attribute1;
};

// Arbitrarily using std::string, not the point of this question
std::string serialize(const A&);


3 commentaires

Je ne pense pas que ce soit possible.


La seule chose à laquelle je pouvais penser serait une affirmation statique quelque part sur la taille de (a). Par conséquent, si quelque chose est ajouté, quelque chose échouera de compiler jusqu'à ce que le nouveau membre de la classe soit sérialisé et que l'affirmation statique ajustée en conséquence.


Vous pouvez ajouter un script ou un programme personnalisé à vos étapes de Makefile ou IDE Pré-Build pour vérifier que tous les membres de la classe sont inclus dans la fonction.


3 Réponses :


2
votes

Si vous utilisez C ++ 1Z, vous pouvez utiliser une liaison structurée: xxx

[Démo en direct]


7 commentaires

Agréable. Recherchez-vous que la fonction de sérialisation utilise ensuite x ?


@Muscampter tant que vous envisagez de sérialiser uniquement les champs publics de la classe, il est relativement facile à effectuer


Je vois que cela fonctionnerait également avec auto & . Que pourrait-on faire sur les députés privés?


@Muscampier Malheureusement, je ne pense pas que cela puisse être étendu aux membres privés / protégés


Je vais essayer de me rappeler que lorsque la plupart des projets industriels sont migrés vers C ++ 17 cinquante ans à partir de maintenant :).


Cet exemple pourrait-il être réécrit dans C ++ 11 à l'aide d'un std :: Cravate ?


@Muscampter non peut faire. std :: cravate permet uniquement d'attribuer à son instance de résultat de std :: tuple



2
votes

Le suivant devrait fonctionner avec C ++ 11.
Un peu délicat en effet, il est basé sur un commentaire de @ Samvarshavchik : xxx

L'idée de base est de répertorier tous les types des membres de données et de définir un nouveau type d'entre eux avec un mixin. Ensuite, il s'agit de mettre un static_assert au bon endroit.
Notez que les membres de données privés sont également pris en compte.

Il existe des cas d'angle qui pourraient le casser, mais peut-être que cela peut fonctionner pour votre code réel.


Note latérale, il peut être encore simplifié si C ++ 14 est une option: xxx


0 commentaires

0
votes

Si vous êtes condamné à utiliser C ++ 11 et vous êtes toujours intéressé par Serializing uniquement les champs publics que vous pouvez créer des tests de trait si le type peut être construit à l'aide d'une initialisation de la liste avec des types de paramètres donnés mais même une autre (de TOUT TYPE):

#include <type_traits>

struct default_param {
    template <class T>
    operator T();
};

template <class T, class...>
using typer = T;

template <class, class, class... Args>
struct cannot_one_more: std::true_type {};

template <class Tested, class... Args>
struct cannot_one_more<typer<void, decltype(Tested{std::declval<Args>()..., default_param{}})>, Tested, Args...>: std::false_type {
};

template <class...>
struct is_list_constructable: std::false_type {};

template <class Tested, class... Args>
struct is_list_constructable<Tested(Args...)>: is_list_constructable<void, Tested, Args...> { };

template <class Tested, class... Args>
struct is_list_constructable<typer<void, decltype(Tested{std::declval<Args>()...}), typename std::enable_if<cannot_one_more<void, Tested, Args...>::value>::type>, Tested, Args...>: std::true_type { };

struct S {
    bool b;
    //bool c; // causes error
};

int main() {
    static_assert(is_list_constructable<S(bool)>::value, "!");
}


0 commentaires