Search code examples
c++11serializationvisual-studio-2015pimpl-idiomcereal

Cereal: how to manage the implementation struct for the PIMPL idiom


I am having troubles to use cereal with the PIMPL idiom.

This is a minimal example:

b.h

#ifndef _B_H_
#define _B_H_

#include <memory>
#include "cereal/types/memory.hpp"
#include "cereal/archives/json.hpp"

struct BImpl;

class B
{
public:
    B();
    ~B();

private:
    std::unique_ptr<BImpl> _impl;

    friend class cereal::access;

    template <class Archive>
    void serialize( Archive& ar )
    {
        ar( CEREAL_NVP( _impl ) );
    }
};

#endif

b.cpp

#include "b.h"

struct BImpl
{
     int b_i = 0;

private:
    friend class cereal::access;

    template <class Archive>
    void serialize( Archive & ar )
    {
        ar(
            CEREAL_NVP( b_i )
          );
    }
};

B::B() : _impl( new BImpl )
{
}

B::~B()
{
}

main.cpp

#include "b.h"
#include <fstream>
#include "cereal/archives/json.hpp"

using namespace std;

int main( int argc, char** argv )
{
    B b1;
    {
        std::ofstream file( "out.json" );
        cereal::JSONOutputArchive archive( file );
        archive( CEREAL_NVP( b1 ) );
    }
}

And here the errors that I get on MSVC 2015 Community Edition when I try to compile the minimal example:

  • C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\type_traits(428): error C2139: 'BImpl': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_polymorphic'

  • C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\type_traits(435): error C2139: 'BImpl': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_abstract'

I am quite sure that I am not the first attempting to do this, but I have not been able to find nothing specific in the documentation or code snippets with a working solution.


Solution

  • I have found a working solution following the approach described here: http://www.boost.org/doc/libs/1_46_1/libs/serialization/doc/pimpl.html

    In practice, I have: * moved the definition of B::serialize to B.cpp * added in B.cpp all the different instantiations for the archives that I use

    Here the ticket that describe the issue: https://github.com/USCiLab/cereal/issues/324