Armadillo Matrizen in einer Klasse mit Namespaces serialisieren (Boost Serialisierung)



  • Hallo zusammen,

    kurz zu meiner Frage: namespaces funktioniert nicht in Klassen, dass habe ich gelesen und ausprobiert, aber mit meiner Situation sieht es so aus, dass ich sie brauche. Also erst mal wollte ich eine Klasse serialisieren. Das habe ich geschafft und alles funktioniert gut. Das ist der Code:

    #include <iostream>
    #include <fstream>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/archive/binary_iarchive.hpp>
    #include <sstream>
    #include <boost/serialization/split_member.hpp>
    
    
    class Gear {
      public:
        template<typename Archive>
        void serialize(Archive& ar, unsigned int version) { ar & v; }
    
        void setV (const double& _v) { v = _v; }
        double getV () { return v; }
    
        void status () { std::cout << "v = " << v << std::endl; }
    
      private:
        double v;
    };
    
    class Car {
      public:
        template<typename Archive>
        void serialize(Archive& ar, unsigned int version) {
          ar & hp;
          ar & x;
        }
    
        void setHP (const int& _hp) { hp = _hp; }
        void setGear (Gear* _Gear) { x = _Gear; }
        void status () { std::cout << "hp = " << hp << " Gear with v = " << x->getV() <<  std::endl; }
    
      private:
        int hp;
        Gear *x;
    };
    
    int main() {
      // Define new Gear:
      Gear* g = new Gear();
      g->setV(2.5);
      g->status();
    
      // Expectation is Car sets up the Gear.
      Car c;
      c.setHP(80);
      c.setGear(g);
      //c.status();
    
    
    
    
      std::ofstream outputStream;
      outputStream.open("bin.dat");
      std::ostringstream oss;
      boost::archive::binary_oarchive oa(outputStream);
      oa & c;
      outputStream.close();
    
      Car b;
      std::ifstream inputStream;
      inputStream.open("bin.dat", std::ifstream::in);
      boost::archive::binary_iarchive ia(inputStream);
      ia & b;
      b.status();
      return 0;
    
    
    }
    

    Und dann ich wollte Armadillo Matrizen serialisieren. Das hat auch geklappt:

    
    
    #include <iostream>
    #include <fstream>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/archive/binary_iarchive.hpp>
    #include <armadillo>
    #include <boost/serialization/split_member.hpp>
    
    BOOST_SERIALIZATION_SPLIT_FREE(arma::mat)
    
    namespace boost { 
    namespace serialization {
    
    template<class Archive>
    void save(Archive & ar, const arma::mat &t, unsigned int version)
    {
        ar & t.n_rows;
        ar & t.n_cols;
        const double *data = t.memptr();
        for(int K=0; K<t.n_elem; ++K)
            ar & data[K];
    }
    
    template<class Archive>
    void load(Archive & ar, arma::mat &t, unsigned int version)
    {
        int rows, cols;
        ar & rows;
        ar & cols;
        t.set_size(rows, cols);
        double *data = t.memptr();
        for(int K=0; K<t.n_elem; ++K)
            ar & data[K];
    }
    }}
    int main() {
    
      arma::mat A = arma::randu<arma::mat>(4,5);
    
      std::ofstream outputStream;
      outputStream.open("bin.dat");
      std::ostringstream oss;
      boost::archive::binary_oarchive oa(outputStream);
      oa & A;
      outputStream.close();
    
      arma::mat B;
      std::ifstream inputStream;
      inputStream.open("bin.dat", std::ifstream::in);
      boost::archive::binary_iarchive ia(inputStream);
      ia & B;
      return 0;
    }
    

    Aber das Problem jetzt ist: ich möchte Arma Matrizen bzw. Arma Datentypen in Klassen und dann sie auch serialisieren. Das funktioniert leider nicht. Ich habe sowas ausprobiert:

    class Car {
      public:
        template<typename Archive>
        void serialize(Archive& ar, unsigned int version) {
          ar & hp;
          ar & x;
        }
    
      namespace boost { 
      namespace serialization {
    
      template<class Archive>
      void save(Archive & ar, const arma::mat &t, unsigned int version)
      {
        ar & t.n_rows;
        ar & t.n_cols;
        const double *data = t.memptr();
        for(int K=0; K<t.n_elem; ++K)
            ar & data[K];
      }
    
      template<class Archive>
      void load(Archive & ar, arma::mat &t, unsigned int version)
      {
        int rows, cols;
        ar & rows;
        ar & cols;
        t.set_size(rows, cols);
        double *data = t.memptr();
        for(int K=0; K<t.n_elem; ++K)
            ar & data[K];
      }
      } }  
    
        arma::mat A;// = arma::randu<arma::mat>(4,5);
    
        void setHP (const int& _hp) { hp = _hp; }
        void setGear (Gear* _Gear) { x = _Gear; }
        void status () { std::cout << "hp = " << hp << " Gear with v = " << x->getV() << A<< std::endl; }
    
      private:
        int hp;
        Gear *x;
    };
    int main() {
    
     Car c;
     c.setHP(80);
     c.setGear(g);
     c.A = arma::randu<arma::mat>(4,5);
    .
    .
    .
    .
    }
    

    Ich bekomme die Fehler:

    g++ -std=c++11 arma_serial_binary_versuch.cpp -larmadillo -lboost_serialization
    arma_serial_binary_versuch.cpp:52:3: error: expected unqualified-id before ‘namespace’                                                     
       namespace boost {                                                                                                                       
       ^                                                                                                                                       
    arma_serial_binary_versuch.cpp:121:1: error: expected ‘}’ at end of input                                                                  
     }                                                                                                                                         
     ^                                                                                                                                         
    arma_serial_binary_versuch.cpp: In member function ‘void Car::serialize(Archive&, unsigned int)’:                                          
    arma_serial_binary_versuch.cpp:48:12: error: ‘hp’ was not declared in this scope                                                           
           ar & hp;
                ^
    arma_serial_binary_versuch.cpp:49:12: error: ‘x’ was not declared in this scope
           ar & x;
                ^
    arma_serial_binary_versuch.cpp: At global scope:
    arma_serial_binary_versuch.cpp:50:5: error: expected unqualified-id at end of input
         }
    

    Im Wesentlichen das Problem ist, dass ich nicht weiß, wie ich ohne die Namespaces Armadillo benutzten kann. Ich habe das hier benutzt:
    https://www.boost.org/doc/libs/1_47_0/libs/serialization/doc/serialization.html#splittingfreefunctions

    um Armadillo zu serialisieren und die Splitting Free Funktionen sind mit Namespaces.

    Ich entschuldige mich, ob ich zu viel Code angegeben habe. Ich wollte nur das gesamte Ziel erklären, weil es sein mag, dass es einfacher geht.



  • Die Funktionen liegen im Namensbereich namespace boost::serialization (als freie Funktionen), damit sie per Name-Lookup gefunden werden können.

    Innerhalb der Car::serialize-Funktion rufst du dann (wie für die anderen Daten) den Serialisierungs-Operator auf:

    class Car {
      public:
        template<typename Archive>
        void serialize(Archive& ar, unsigned int version) {
          ar & hp;
          ar & x;
          ar & A;
        }
    


  • Danke Th69. Ich kann das leider so nicht machen, weil n_{cols,rows,elems} sind alle Konstanten. Deswegen musste ich dieses "save" und "load" Funktionen benutzten. Arma hat keine Unterstützung für Serialisierung. Vielleicht ist es problematisch was ich tue: ich benutzt void serialize() fürs Serialisieren und auch void save und load, die miteinander nicht zu tun haben.



  • Die Funktionen load und save aus deinem 2. Code solltest du ja so lassen.

    Was genau paßt denn nicht, wenn du die serialize-Funktion um ar & A;erweiterst?



  • Die Fehler mit ar &A; sind genauso, wenn ar & A; nicht da ist. Hier ist der Fehler wieder:

    g++ -std=c++11 red_versuch_bin_arma.cpp -larmadillo -lboost_serialization
    red_versuch_bin_arma.cpp:34:3: error: expected unqualified-id before ‘namespace’
       namespace boost { 
       ^
    red_versuch_bin_arma.cpp:105:1: error: expected ‘}’ at end of input
     }
     ^
    red_versuch_bin_arma.cpp: In member function ‘void Car::serialize(Archive&, unsigned int)’:
    red_versuch_bin_arma.cpp:29:12: error: ‘hp’ was not declared in this scope
           ar & hp;
                ^
    red_versuch_bin_arma.cpp:30:12: error: ‘x’ was not declared in this scope
           ar & x;
                ^
    red_versuch_bin_arma.cpp:31:12: error: ‘A’ was not declared in this scope
           ar & A;
                ^
    red_versuch_bin_arma.cpp: At global scope:
    red_versuch_bin_arma.cpp:32:5: error: expected unqualified-id at end of input
         }
    

    Also das Problem ist mit den Namespaces (ich glaube). Um ausführlich zu sein, hier ist der gesamte Code (inkl. ar& A;):

    #include <iostream>
    #include <fstream>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/archive/binary_iarchive.hpp>
    #include <sstream>
    #include <boost/serialization/split_member.hpp>
    #include <armadillo>
    
    BOOST_SERIALIZATION_SPLIT_FREE(arma::mat)
    
    class Gear {
      public:
        template<typename Archive>
        void serialize(Archive& ar, unsigned int version) { ar & v; }
    
        void setV (const double& _v) { v = _v; }
        double getV () { return v; }
    
        void status () { std::cout << "v = " << v << std::endl; }
    
      private:
        double v;
    };
    
    class Car {
      public:
        template<typename Archive>
        void serialize(Archive& ar, unsigned int version) {
          ar & hp;
          ar & x;
          ar & A;
        }
    
      namespace boost { 
      namespace serialization {
    
      template<class Archive>
      void save(Archive & ar, const arma::mat &t, unsigned int version)
      {
        ar & t.n_rows;
        ar & t.n_cols;
        const double *data = t.memptr();
        for(int K=0; K<t.n_elem; ++K)
            ar & data[K];
      }
    
      template<class Archive>
      void load(Archive & ar, arma::mat &t, unsigned int version)
      {
        int rows, cols;
        ar & rows;
        ar & cols;
        t.set_size(rows, cols);
        double *data = t.memptr();
        for(int K=0; K<t.n_elem; ++K)
            ar & data[K];
      }
      } }  
    
        arma::mat A;// = arma::randu<arma::mat>(4,5);
    
        void setHP (const int& _hp) { hp = _hp; }
        void setGear (Gear* _Gear) { x = _Gear; }
        void status () { std::cout << "hp = " << hp << " Gear with v = " << x->getV() << A<< std::endl; }
    
        private:
        int hp;
        Gear *x;
    };
    
    
    
    
    
    int main() {
      // Define new Gear:
      Gear* g = new Gear();
      g->setV(2.5);
      g->status();
    
      // Expectation is Car sets up the Gear.
      Car c;
      c.setHP(80);
      c.setGear(g);
      c.A = arma::randu<arma::mat>(4,5);
      //c.status();
    
    
      std::ofstream outputStream;
      outputStream.open("bin.dat");
      std::ostringstream oss;
      boost::archive::binary_oarchive oa(outputStream);
      oa & c;
      outputStream.close();
    
      Car b;
      std::ifstream inputStream;
      inputStream.open("bin.dat", std::ifstream::in);
      boost::archive::binary_iarchive ia(inputStream);
      ia & b;
      b.status();
      return 0;
    
    
    }
    


  • @mika000 sagte in Armadillo Matrizen in einer Klasse mit Namespaces serialisieren (Boost Serialisierung):

    Also das Problem ist mit den Namespaces (ich glaube)

    Ja. Namespace in Klasse ist nicht.



  • @Swordfish gibt es eine Zwsichenlösung dann?



  • Ohne mich mit boost::serialization auszukennen: Müssen saveund load Member Funktionen sein? Soweit ich sehe hast du da keinen direkten Zugriff auf Klassenmember? Also genau so, wie @Th69 das beschrieben hat.



  • @mika: Viel Erfahrung mit C++ scheinst du nicht zu haben?!

    Du sollst die beiden Funktionen ja auch außerhalb der Klasse als freie Funktionen definieren (also so wie in deinem 2. Code)!



  • Ach! Ja klar. Doofer Fehler bei mir. Und ja nicht so viele Erfahrungen mit C++ aber ich gebe mir viel Mühe meine Programmier-Fähigkeiten zu verbessern. Vielen Dank Th69! Der Code funktioniert jetzt. Das wichtigste war einfach ar& A; hinzuzufügen.


Log in to reply