2

I am trying to create a game save system using boost serialization, and want to create an easy way for clients to select member variables for serialization.

Basically I want the user to input something like this:

class apple : public Actor
{
public:
     int a;
     bool isTasty;
     float unimportantData;


     SET_SAVED_MEMBERS(a, isTasty);
};

And I would like this to be expanded into something like

class apple : public Actor
{
public:
   // ...

   template<typename Archive>
   void serialize(Archive& arch, const unsigned int version)
   {
        arch & BOOST_SERIALIZATION_NVP(a);
        arch & BOOST_SERIALIZATION_NVP(isTasty);

}

Of course, it is fine if it requires a few more macros than this.

I'm fine with template meta programming (preferably) or preprocessor meta programming.

C++11 is fine, too.

Thanks for the help!

5
  • if BOOST_SERIALIZATION_NVP is a c preprocessor macro, you have no chance with using template parms, simply because the evaluation of macros will be done before templates are expanded. But I also did not understand what your problem is. Do you only want to write less code by hand? Commented Jun 19, 2015 at 15:11
  • Correct. I have a few ideas now though. Once I saw somebody typedef a boost::mpl container and then write a macro that defines a function that uses fusion to iterate through the elements. Is this possible? Commented Jun 19, 2015 at 15:28
  • @Klaus I'm not sure I understand why this cannot be done with templates... as long as the macro doesn't do anything particularly odd, it should expand inside the template definition and then the expansion would be applied multiple times, no? Commented Jun 19, 2015 at 16:00
  • Yes, the macro expansion is trivial. It would expand to ::boost::serialization::make_nvp("a", a); Commented Jun 19, 2015 at 16:01
  • I thought about a solution which uses variadic template parms, but this couldn't work because the macro expands before the template expands. And also it is impossible to have "names" from vars in the macro, because all the parms defined with <typename ... T> void X(T...a ) have the name a which is not helpful in this use case. Commented Jun 19, 2015 at 16:26

1 Answer 1

2

Previously I had a boost-focused answer that I wasn't able to test. Here's something more comprehensible using a combination of template meta-programming and macros:

#include <iostream>

// Build a base template for the save Implementation
template <typename... ARG_TYPES>
struct save_impl;

// Create a DoSerialize function that will recursively serialize all objects.
template <typename Archive, typename FIRST_TYPE, typename... OTHER_TYPES>
struct save_impl<Archive, FIRST_TYPE, OTHER_TYPES...> {
  static void DoSerialize(Archive& arch, FIRST_TYPE & arg1, OTHER_TYPES&... others) {
    // Instead of printing in the next line, do:  arch & BOOST_SERIALIZATION_NVP(a);
    std::cout << arch << arg1 << std::endl;
    save_impl<Archive, OTHER_TYPES...>::DoSerialize(arch, others...);
  }
};

// Base case to end recursive call of struct-based DoSerialize
template <typename Archive>
struct save_impl<Archive> {
  static void DoSerialize(Archive& arch) { ; }
};

// Create a DoSerialize function that will call struct-based implementation.
template <typename Archive, typename... ARG_TYPES>
void DoSerialize(Archive & arch, ARG_TYPES&... args) {
  save_impl<Archive, ARG_TYPES...>::DoSerialize(arch, args...);
}

// Create the desired macro to add the serialize function to a class.
#define SET_SAVED_MEMBERS(...)         \
  template<typename Archive>           \
  void serialize(Archive& arch) {      \
    DoSerialize(arch, __VA_ARGS__);    \
  }

Currently I have it just printing so I could test it (but indicate above the line you would need to change). Here is a test using your apple example:

class apple {
public:
  int a;
  bool isTasty;
  float unimportantData;

  SET_SAVED_MEMBERS(a, isTasty);
};


int main() {
  apple a = {7, false, 2.34};
  a.isTasty=true;
  a.serialize("Archive: ");
}

Note that I'm sending in a string instead of an archive object -- that works fine with the fact that it's currently using print.

Sign up to request clarification or add additional context in comments.

2 Comments

Nice, will test out before selecting as correct answer.
Looks great. +1 because it is passed by reference. This is important for the loading aspect. Thanks a lot!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.