Carrying on from:Yet another C++ Json ParserYet another C++ Json Parser (Recursive)All the code is available from git hub: ThorsSerializer but only reviewing a small section here.The idea is that using this library it should be easy to define how a class is serialized without writing any code. See example in README#ifndef THORSANVIL_SERIALIZE_JSON_SERIALIZE_H#define THORSANVIL_SERIALIZE_JSON_SERIALIZE_H/* Content: * * Used to define how a class is imported/exported via the Json Serialized * * Conventions: *      T:      The type of the base class *      I:      The type of the member *      MP:     The type of the member pointer * *      S:      Source type (std::ostream output) (ThorsAnvil::Json::ScannerSax input) * * Every type that is serializeable has a class JsonSerializeTraits. * For basic types (int/float etc) no definition is required and the default template version works * For compound types you need to define the type SerializeInfo. *      SerializeInfo:           It is a mpl vector of types. *                              Each type (in the vector) defines how to serialize *                              a member of the compound type. * * Boilerplate  code to create the appropriate types for SerializeInfo. *      #define THORSANVIL_SERIALIZE_JsonAttribute(className, member) * * Example: *      class MyClass *      { *          // STUFF * *          // If any members are private and need to be serialized then *          // JsonSerializeTraits<MyClass> must be a friend of the class so it can generate the appropriate code * *          friend class JsonSerializeTraits<MyClass>; *      }; * *      namespace ThorsAnvil { namespace Serialize { namespace Json { *      template<> *      class JsonSerializeTraits<MyClass> *      { *          static ThorsAnvil::Serialize::Json::JsonSerializeType const  type    = Map; * *          THORSANVIL_SERIALIZE_JsonAttribute(MyClass, member1); *          THORSANVIL_SERIALIZE_JsonAttribute(MyClass, member2); *          THORSANVIL_SERIALIZE_JsonAttribute(MyClass, member3); *          typedef boost::mps::vector<member1, member2, member3>   SerializeInfo; *      }; *      }}} * * Now we can serialize/deserialize with: *      std::cout << jsonExport(myClassObj) << \n; *      std::cin  >> jsonInport(myClassObj); * * Same for std::vector *      std::vector<MyClass>  vec;  // Will serialize any fundamental type or type with JsonSerializeTraits<> specialized for it *                                  // If JsonSerializeTraits<> is not specialized for a compound type you get a compile time *                                  // error *      std::cout << jsonExport(vec) << \n; *      std::cin  >> jsonImport(vec); */#include json/ScannerSax.h#include json/ParserShiftReduce.tab.hpp#include <boost/mpl/at.hpp>#include <boost/mpl/pop_front.hpp>#include <boost/mpl/for_each.hpp>#include <boost/mpl/vector.hpp>#include <boost/mpl/bool.hpp>#include <boost/type_traits/is_fundamental.hpp>#include <boost/typeof/typeof.hpp>#include <iostream>/* * Helper Macros: *  * These are macros that will build some boilerplate types needed by the serialization code. * * THORSANVIL_SERIALIZE_JsonAttribute:          This is the main macro used. *                                              It identifies a class member that will be serialized * * THORSANVIL_SERIALIZE_JsonAttribute_1:        Used internally (should probably not be used by others). * THORSANVIL_SERIALIZE_JsonAttributeAccess:    If you want to run some code to as part of the serialization processes *                                              this macro allows you to specify a type that will be used during serialization. *                                              Examples will be provided in the documentaion. * * THORSANVIL_SERIALIZE_JsonGenericMapAttributeAccess:  A generic accessor can be used to generate multiple items. *                                                      When de-serializing the Json can be applied to multiple elements. *                                                      Used manly for container classes like std::map *THORSANVIL_SERIALIZE_JsonGenericArrAttributeAccess:   A generic accessor used by for arrays rather than maps (std::vector) *                                                      But otherwise identical to THORSANVIL_SERIALIZE_JsonGenericMapAttributeAccess */#define THORSANVIL_SERIALIZE_JsonAttribute(className, member)                                                                           \    typedef BOOST_TYPEOF(((className*)01)->member)    JsonAttribute ## member ## Type;                                                  \    THORSANVIL_SERIALIZE_JsonAttribute_1(className, member, JsonSerializeTraits<JsonAttribute ## member ## Type>)#define THORSANVIL_SERIALIZE_JsonAttribute_1(className, member, SerTraits)                                                              \    typedef BOOST_TYPEOF(&className::member)            JsonAttribute ## member ## TypePtr;                                             \    typedef JsonSerialElementAccessor<className, JsonAttribute ## member ## TypePtr, SerTraits>  JsonAttribute ## member ## Accessor;   \    struct member: JsonSerializeItem<className, JsonAttribute ## member ## Accessor, std::string>                                       \    {                                                                                                                                   \        member()                                                                                                                        \            : JsonSerializeItem<className, JsonAttribute ## member ## Accessor, std::string>(#member, &className::member)               \        {}                                                                                                                              \    }#define THORSANVIL_SERIALIZE_JsonAttributeAccess(className, member, accessor)                                                           \    struct member: JsonSerializeItem<className, accessor, std::string>                                                                  \    {                                                                                                                                   \        member()                                                                                                                        \            : JsonSerializeItem<className, accessor, std::string>(#member, accessor())                                                  \        {}                                                                                                                              \    }#define THORSANVIL_SERIALIZE_JsonGenericMapAttributeAccess(className, accessor)                                                         \    struct genericAccessor: JsonSerializeItem<className, accessor, std::string>                                                         \    {                                                                                                                                   \        genericAccessor()                                                                                                               \            : JsonSerializeItem<className, accessor, int>(-1 , accessor())                                                              \        {}                                                                                                                              \    }namespace ThorsAnvil{    namespace Serialize    {        /* External dependencies from the generic Serialization code */        template<typename T, typename Parser>        struct Importer;        template<typename T, typename Printer>        struct Exporter;        namespace Json        {/* Three basic element types:   Invalid (this obejct is not a top level JSON object) *                              Map     A JSON object   { [<string> : <value> [, <string> : <value>]*]? } *                              Array   A JSON array    [ [<value> [, <value>]*]? ] */enum JsonSerializeType {Invalid, Map, Array};/* * All objects that want to be serialized by this code must define their own specialization of this class. * The default version will cause compilation errors. Which hopefully will bring the reader here. */template<typename T>struct JsonSerializeTraits{    static JsonSerializeType const  type    = Invalid;    typedef T                     SerializeInfo;};// Forward declarationstemplate<typename T, typename A, typename RegisterKey>struct JsonSerializeItem;/* Class used by boost::mpl::for_each. Nothing special simple lamba's will replace them in the future *//* *  T       The object Type *  S       The source type (parser or std::ostream) * * This is basically trying to templatize and remove the need for multiple action objects that * are called from mpl::for_each */template<typename T, typename S>struct MPLForEachActivateTrait;template<typename T>struct MPLForEachActivateTrait<T, std::ostream>{    typedef const T                 ObjectType;    static int const                SerializeActionIndex    = 0;};template<typename T>struct MPLForEachActivateTrait<T, ThorsAnvil::Json::ScannerSax>{    typedef T                       ObjectType;    static int const                SerializeActionIndex    = 1;};template<typename T, typename S>class MPLForEachActivateItem{    typedef          MPLForEachActivateTrait<T, S>  Traits;    typedef typename Traits::ObjectType             ObjectType;    S&              pump;    ObjectType&     object;    public:        MPLForEachActivateItem(S& p, ObjectType& obj)            : pump(p)            , object(obj)        {}        // Depending on if the pump is a stream or a scanner        // Calls      JsonSerialize::activate()        // or         JsonDeSerialize::activate()        template<typename SerializeItem>        void operator()(SerializeItem const& item) const        {            typedef typename boost::mpl::at_c<typename SerializeItem::SerializeType, Traits::SerializeActionIndex>::type  SerializeAction;            SerializeAction::activate(item, pump, object);        }};/* * Objects of this type get stored in the *      JsonSerializeTraits::SerializeInfo *  This is what the user create with the macros above. The default A is JsonSerialElementAccessor *  But user can define their own action for complex objects This wrapper is merely a vehicle for *  calling the A methods in a controlled manner. * * Note: These classes are not designed to be used directly but via the macros: *          THORSANVIL_SERIALIZE_JsonAttribute *          THORSANVIL_SERIALIZE_JsonAttributeAccess *  See the notes by these macros for details */template<typename T, typename A, typename RegisterKey, JsonSerializeType type = JsonSerializeTraits<T>::type>struct JsonSerialize;template<typename T, typename A, typename RegisterKey>struct JsonSerialize<T, A, RegisterKey, Map>{    // Generic serialization of a JSON object    static void activate(JsonSerializeItem<T, A, RegisterKey> const& item, std::ostream& stream, T const& src)    {        if (!item.first)        {   stream << ',';        }        stream << '' << item.memberName << '' << :;        item.accessor.serialize(src, stream);    }};template<typename C, typename A, typename RegisterKey>struct JsonSerialize<C, A, RegisterKey, Array>{    // Generic serialization of a JSON array    static void activate(JsonSerializeItem<C, A, RegisterKey> const& item, std::ostream& stream, C const& src)    {        if (!item.first)        {   stream << ',';        }        item.accessor.serialize(src, stream);    }};template<typename T, typename A,typename RegisterKey, JsonSerializeType type = JsonSerializeTraits<T>::type>struct JsonDeSerialize;template<typename T, typename A,typename RegisterKey>struct JsonDeSerialize<T, A, RegisterKey, Map>{    static void activate(JsonSerializeItem<T, A, RegisterKey> const& item, ThorsAnvil::Json::ScannerSax& parser, T& dst)    {        std::auto_ptr<ThorsAnvil::Json::SaxAction>    action(item.accessor.action(dst));        parser.registerAction(item.memberName, action);    }};template<typename T, typename A>struct JsonDeSerialize<T, A, int, Array>{    static void activate(JsonSerializeItem<T, A, int> const& item, ThorsAnvil::Json::ScannerSax& parser, T& dst)    {        std::auto_ptr<ThorsAnvil::Json::SaxAction>    action(item.accessor.action(dst));        parser.registerActionOnAllArrItems(action);    }};template<typename T, typename A>struct JsonDeSerialize<T, A, std::string, Array>{    static void activate(JsonSerializeItem<T, A, std::string> const& item, ThorsAnvil::Json::ScannerSax& parser, T& dst)    {        std::auto_ptr<ThorsAnvil::Json::SaxAction>    action(item.accessor.action(dst));        parser.registerActionNext(action);    }};/* * A type holder object that picks up the correct versions of JsonSerialize and JsonDeSerialize * Used by MPLForEachActivateItem to get the correct type */template<typename T, typename A, typename RegisterKey>struct JsonSerializeItem{    RegisterKey memberName;    A           accessor;    bool        first;    JsonSerializeItem(RegisterKey const& name, A const& ac): memberName(name), accessor(ac), first(false) {}    JsonSerializeItem& makeFirst() {first = true;return *this;}    typedef    JsonSerialize<T,A,RegisterKey>       Serialize;    typedef    JsonDeSerialize<T,A,RegisterKey>     DeSerialize;    typedef boost::mpl::vector<Serialize, DeSerialize>      SerializeType;};/* * Importing * ============ * * The JsonImportAction defines a class that is registered with a Json SAX parser * so that we can register callback actions for particular attributes. * * For fundamental types json is read directly into the value. * For compound types when the attribute is reached additional callbacks are registered * for each of the compound members that needs to be de-serialized (this is done recursively) * So we can de-serialize arbitrary json structures. */template<typename SerializeInfo, typename I, bool EnablePod = boost::is_fundamental<I>::value>class JsonImportAction: public ThorsAnvil::Json::SaxAction{    I&              memberRef;    public:        JsonImportAction(I& mr)            : memberRef(mr)        {}        virtual void doPreAction(ThorsAnvil::Json::ScannerSax&, ThorsAnvil::Json::Key const&){}        virtual void doAction(ThorsAnvil::Json::ScannerSax&, ThorsAnvil::Json::Key const&, JsonValue const& value)        {            // Read fundamental type directly into the member            memberRef   = value.getValue<I>();        }};template<typename SerializeInfo, typename I>class JsonImportAction<SerializeInfo, I, false>: public ThorsAnvil::Json::SaxAction{    I&              memberRef;    public:        JsonImportAction(I& mr)            : memberRef(mr)        {}        virtual void doAction(ThorsAnvil::Json::ScannerSax&, ThorsAnvil::Json::Key const&, JsonValue const&){}        virtual void doPreAction(ThorsAnvil::Json::ScannerSax& parser, ThorsAnvil::Json::Key const&)        {            // Compound type. Register callback for each member.            //                This is done when the attribute is reached in json not before            boost::mpl::for_each<SerializeInfo>(MPLForEachActivateItem<I, ThorsAnvil::Json::ScannerSax>(parser, memberRef));        }};/* * Need a function template to create the correct JsonImportAction() */template<typename SerializeInfo, typename T, typename I>ThorsAnvil::Json::SaxAction* new_JsonImportAction(T& dst, I T::* memberPtr){    return new JsonImportAction<SerializeInfo, I>(dst.*memberPtr);}/* Default Serialization Traits: * Used by all types without their own specific serialization traits. */template<JsonSerializeType>struct JsonSerializeBrace{    static char braces[];};/* * The MemberScanner is used to register callbacks that will read sub-members from the json object */template<typename T, typename MemberToSerialize = typename JsonSerializeTraits<T>::SerializeInfo>struct MemberScanner{    void operator()(ThorsAnvil::Json::ScannerSax& scanner, T& destination)    {        boost::mpl::for_each<typename JsonSerializeTraits<T>::SerializeInfo>(MPLForEachActivateItem<T, ThorsAnvil::Json::ScannerSax>(scanner, destination));    }};template<typename T>struct MemberScanner<T, T>{    // A normal type with no SerializeInfo has no members thus no need to register callbacks.    void operator()(ThorsAnvil::Json::ScannerSax& scanner, T& destination)    {}};template<typename T>struct MemberScanner<T, void>{    // A normal type with no SerializeInfo has no members thus no need to register callbacks.    void operator()(ThorsAnvil::Json::ScannerSax& scanner, T& destination)    {}};/* * The MemberPrinter prints each member of an object. */template<typename T, typename MemberToSerialize = typename JsonSerializeTraits<T>::SerializeInfo>struct MemberPrinter{    void operator()(std::ostream& stream, T const& source)    {        typedef typename boost::mpl::at<typename JsonSerializeTraits<T>::SerializeInfo, boost::integral_constant<int,0> >::type  FirstType;        typedef typename boost::mpl::pop_front<typename JsonSerializeTraits<T>::SerializeInfo>::type                             AllButFirstType;        MPLForEachActivateItem<T, std::ostream>     itemPrinter(stream, source);        // Print the first member (Call makeFirst() means no comma is printed)        itemPrinter(FirstType().makeFirst());        // For each of the other members use a loop a proceed each object with a comma        boost::mpl::for_each<AllButFirstType>(itemPrinter);    }};template<typename T>struct MemberPrinter<T, T>{    // A normal object just prints itself.    void operator()(std::ostream& stream, T const& source)    {        stream << source;    }};template<typename T>struct MemberPrinter<T, void>{    void operator()(std::ostream& stream, T const& source)    {}};struct JsonSerializer{    template<typename T, JsonSerializeType base = JsonSerializeTraits<T>::type>    struct Parser: ThorsAnvil::Json::ScannerSax    {        typedef boost::mpl::bool_<base != Invalid>      Parsable;        Parser(T& dst)            : destination(dst)        {            MemberScanner<T>    memberScanner;            memberScanner(*this, destination);        }        void parse(std::istream& stream)        {            ScannerSax::parse<yy::ParserShiftReduce>(stream);        }        T&  destination;    };    template<typename T ,JsonSerializeType base = JsonSerializeTraits<T>::type>    struct Printer    {        typedef boost::mpl::bool_<base != Invalid>      Printable;        Printer(T const& src)            : source(src)        {}        void print(std::ostream& stream)        {            stream << JsonSerializeBrace<base>::braces[0];            MemberPrinter<T>    memberPrinter;            memberPrinter(stream, source);            stream << JsonSerializeBrace<base>::braces[1];        }        T const&    source;    };};/* * Default accessors for fundamental types std::string * The serialize()  Recursively calls jsonInternalExport() on the member to serialize the member. * * The action()     Creates a JsonImportAction() that is registered with the SAX parser that just reads the *                  Item directly into the object. If the object is a compound type it uses the SerializeInfo *                  to register subsequent actions recursively so we always read directly into an object *                  not a copy. */template<typename T, typename MP, typename SerTraits>class JsonSerialElementAccessor{    MP          memberPtr;    public:    JsonSerialElementAccessor(MP mp): memberPtr(mp)    {}    void serialize(T const& src, std::ostream& stream) const    {        stream << jsonInternalExport(src.*memberPtr);    }    std::auto_ptr<ThorsAnvil::Json::SaxAction>      action(T& dst) const    {        std::auto_ptr<ThorsAnvil::Json::SaxAction>  action(new_JsonImportAction<typename SerTraits::SerializeInfo>(dst, memberPtr));        return action;    }};/* Helper functions */template<typename T>Importer<T, typename JsonSerializer::template Parser<T> >   jsonInternalImport(T& object){    return Importer<T, typename JsonSerializer::template Parser<T> >(object);}template<typename T>Exporter<T, typename JsonSerializer::template Printer<T> >  jsonInternalExport(T const& object){    return Exporter<T, typename JsonSerializer::template Printer<T> >(object);}        }    }}#endif
JSON Serializer
c++;json;template meta programming;serialization