0

I'm making a multiplayer game, the Server stores it's game world state as various std::unordered_map in a class called ServerWorldState.

The server is composed by a single class called Game, which contains ServerWorldState.

Currently I'm trying to make Save() and Load() functions, which for now will be in the Game class. These functions are supposed to save certain data from the maps within ServerWorldState into a binary archive, for this purpose, I'm using Cereal library for serialization and the standard file IO streams.

Cereal requires a serialize method to be present in a class, in order for members to be specified for serialization:

ServerWorldState.h

class ServerWorldState : public World
{
private:
    std::unordered_map<int, ServerProp> props;
public:
    template<class Archive>
    void serialize(Archive& archive);

};

ServerWorldState.cpp

template<class Archive>
void ServerWorldState::serialize(Archive& archive)
{
    archive(props); //Serialize things by passing them to the archive
}

The ServerProp class actually has another serialize method within itself. I'm unsure if this is correct for specifying with further depth what object members should get serialized.

Save function from Game (load works very similar and has same problem, but since I haven't finished it's design I'm only showing save):

Game.h

class Game
{
private:
    std::shared_ptr<ServerWorldState> currentWorld;
public:
    bool Save();
};

Game.cpp

bool Game::Save()
{
    std::ofstream outfile("level.dat", std::ios::binary | std::ios::out);
    if (!outfile) {
        std::cout << "SERVER_WORLD_STATE::SAVE: Could not open world.dat file for saving!" << std::endl;
        return false;
    }

    {
        cereal::PortableBinaryOutputArchive oarchive(outfile); //Create an output archive

        oarchive(currentWorld); //Write data to the archive

    } //Archive goes out of scope, ensuring all contents are flushed

    outfile.close();

    return true;
}

In essence I want to serialize/deserialize and binary save/load the std::unordered_map in ServerWorldState, but I get this link error:

Error LNK2019 unresolved external symbol "public: void __cdecl ServerWorldState::serialize(class cereal::PortableBinaryOutputArchive &)" (??$serialize@VPortableBinaryOutputArchive@cereal@@@ServerWorldState@@QEAAXAEAVPortableBinaryOutputArchive@cereal@@@Z) referenced in function "public: static void __cdecl cereal::access::member_serialize(class cereal::PortableBinaryOutputArchive &,class ServerWorldState &)" (??$member_serialize@VPortableBinaryOutputArchive@cereal@@VServerWorldState@@@access@cereal@@SAXAEAVPortableBinaryOutputArchive@1@AEAVServerWorldState@@@Z) - Game.obj line 1

I would asume this would show if the serialize method wasn't defined, but it is. I also thought I might be missing some inclusion, but I seem to have all in order.

Mithrandir
  • 33
  • 6
  • Move the template method definition from `ServerWorldState.cpp` to `ServerWorldState.h`. See also [this question](https://stackoverflow.com/q/495021/501250). The compiler needs to see the template definition when it is instantiated in order to generate the instantiation. – cdhowie May 24 '20 at 23:12
  • That indeed fixes it. Not entirely sure how I feel about the actual definition being in the .h though. I actually read it may be faster, but I'm used to always having definitions in .cpp – Mithrandir May 25 '20 at 15:48
  • Some like to put template definitions in a `.tpp` file and include it at the end of the header. (Note that the `.tpp` file is not a compilation unit.) Unfortunately, there is no way around the compiler needing the definition at the point of instantiation, unless you add all of the necessary explicit instantiations in the `.cpp` file. – cdhowie May 26 '20 at 05:06

0 Answers0