2016-12-08 2 views
1

(Для простоты, сериализатор будет называться записью и десериализатор будет называться чтения)C++ сериализатора с шаблоном и полиморфизмом

Я пишу C++ игры сериалайзер с нуля, без библиотеки допускается.

Основная проблема, которую я имею, заключается в том, чтобы сохранить синхронизацию чтения и записи (значения чтения должны быть такими же, как и записанные). Таким образом, Packer обрабатывает обе задачи и указан с перечислением.

Что я имею

enum PackerType { 
    WRITE, 
    READ 
} 

template <PackerType PType> 
class Packer { 
    char *buffer; // Packer will write here 
    uint32_t index; 

    template <typename T> 
    void Pack(T & value); // Calls appropriate functions depending on PType 
} 

Что я хочу быть в состоянии сделать

class ElementToSerialize : ISeriablizable { 

    virtual void WriteAndRead(Packer & p) { 
     p.Pack(32); 
     p.Pack("Hello World"); 
    } 
} 

Packer<WRITE> wpacker; 
Packer<READ> rpacker; 
rpacker.buffer = wpacker.buffer; 

WriteAndRead(wpacker); // Will write everything in wpacker.buffer 
WriteAndRead(rpacker); // Will read wpacker.buffer 

Так я знаю, что это не возможно в C++, но то, что я ищу элегантный способ решения этой проблемы. Я уже знаю о стирании стилей, но я не поклонник этого решения.

+0

одно приемлемое решение: вы можете изменить 'WriteAndRead' в шаблон. –

+1

Я не обязательно вижу необходимость использования шаблонов здесь, вы можете просто сохранить в члене объекта Packer ли это писатель или читатель и заставить его действовать соответственно во время выполнения. – Steeve

+0

@appleapple, хотя он не указан в примере, эта функция должна быть виртуальной. Я добавлю его, чтобы быть яснее. – aguadoe

ответ

2

Как насчет начиная с чем-то например:

class IPacker 
{ 
public: 
    virtual void Pack(int& value) = 0; 
    virtual void Pack(float& value) = 0; 
} 

class ISeriablizable 
{ 
public: 
    virtual void Serialize(IPacker & p) = 0; 
} 

class WritePacker : public IPacker 
{ 
    char* buffer; 
    int index = 0; 
public: 
    WritePacker(char* buffer) : buffer(buffer) {} 
    void Pack(int& value) override { /* write to buffer */ } 
    void Pack(float& value) override { /* write to buffer */ } 
} 

class ReadPacker : public IPacker 
{ 
    char* buffer; 
    int index = 0; 
public: 
    ReadPacker(char* buffer) : buffer(buffer) {} 
    void Pack(int& value) override { /* read from buffer */ } 
    void Pack(float& value) override { /* read from buffer */ } 
} 

class ElementToSerialize : public ISeriablizable 
{ 
    int x = 32; 
    std::string y = "Hello world"; 

    void Serialize(IPacker & p) override 
    { 
     p.Pack(x); 
     p.Pack(y); 
    } 
} 
+0

Я надеялся сохранить шаблоны, чтобы гарантировать полную поддержку всех типов, но, похоже, мне придется ограничить себя. Я пойду с этим, спасибо! – aguadoe

+1

В IPacker вы можете добавить метод: virtual Pack (void * data, size_t size) = 0; Затем добавьте шаблон void Pack (T & value) {Pack (& ​​value, sizeof (value)); –

+0

Но ... это работает только в том случае, если T - простой тип данных. Если это std :: string или какой-либо другой тип, содержащий указатель на другие данные, это не сработает. –

1

Если это не является обязательным требованием, вы могли бы избежать использования шаблонов в целом, и просто хранить ли пакера read или write, чтобы вы знали его во время выполнения (пример):

class Packer { 
public: 
    enum Type { 
     READ, 
     WRITE 
    }; 

    char *buffer; // Packer will write here 
    uint32_t index; 
    Type type; 

    Packer(Type t) : type(t) {} 

    void Pack(int& value); 
    void Pack(float& value); 
    void Pack(std::string& value); 
    // etc... 
}; 
+0

Это модель, которую я использую в настоящее время, но она не очень ощущается OO-ish. Я очень ищу элегантный способ сделать это, не делая 'if (type == WRITE)' – aguadoe

Смежные вопросы