Boost serialization

Pages: 1234
Thanks for the tip. I made the change to class Porsche : public Car<Archive>

and got some errors that the ar & components of the derived serialize() functions are not defined. So I uncommented //template<class Archive> on lines 68 and 86 and these errors went way. Now I am getting the following errors:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
virtuell_funk_seri.cpp:69:20: error: declaration of template parameter ‘Archive’ shadows template parameter
           template<class Archive>
                    ^~~~~
virtuell_funk_seri.cpp:61:10: note: template parameter ‘Archive’ declared here
 template<class Archive>
          ^~~~~
virtuell_funk_seri.cpp:87:22: error: declaration of template parameter ‘Archive’ shadows template parameter
             template<class Archive>
                      ^~~~~
virtuell_funk_seri.cpp:77:10: note: template parameter ‘Archive’ declared here
 template<class Archive>
          ^~~~~
virtuell_funk_seri.cpp: In function ‘int main()’:
virtuell_funk_seri.cpp:100:32: error: invalid new-expression of abstract class type ‘Audi<main()::Archive>’
   Audi<class Archive>* a = new Audi<class Archive>;
                                ^~~~~~~~~~~~~~~~~~~
virtuell_funk_seri.cpp:78:7: note:   because the following virtual functions are pure within ‘Audi<main()::Archive>’:
 class Audi : public Car<Archive>
       ^~~~
virtuell_funk_seri.cpp:56:20: note:     void Car<Archive>::serialize(Archive&, unsigned int) [with Archive = main()::Archive]
       virtual void serialize(Archive& ar, unsigned int version) = 0;
                    ^~~~~~~~~
virtuell_funk_seri.cpp:101:35: error: invalid new-expression of abstract class type ‘Porsche<main()::Archive>’
   Porsche<class Archive>* b = new Porsche<class Archive>;
                                   ^~~~~~~~~~~~~~~~~~~~~~
virtuell_funk_seri.cpp:62:7: note:   because the following virtual functions are pure within ‘Porsche<main()::Archive>’:
 class Porsche : public Car<Archive>
       ^~~~~~~
virtuell_funk_seri.cpp:56:20: note:     void Car<Archive>::serialize(Archive&, unsigned int) [with Archive = main()::Archive]
       virtual void serialize(Archive& ar, unsigned int version) = 0;
                    ^~~~~~~~~
virtuell_funk_seri.cpp:125:32: error: invalid new-expression of abstract class type ‘Audi<main()::Archive>’
   Audi<class Archive>* c = new Audi<class Archive>;
                                ^~~~~~~~~~~~~~~~~~~
virtuell_funk_seri.cpp:126:35: error: invalid new-expression of abstract class type ‘Porsche<main()::Archive>’
   Porsche<class Archive>* d = new Porsche<class Archive>;



I also changed

1
2
Audi<class Archive>* a = new Audi<class Archive>;


to

 
Audi<Archive>* a = new Audi<Archive>;


but that is causing a lot errors so I assume it is not correct but I agree with you that it makes sense to change that part as well.
Last edited on
I also changed

Audi<class Archive>* a = new Audi<class Archive>;

to

Audi<Archive>* a = new Audi<Archive>;

but that is causing a lot errors so I assume it is not correct but I agree with you that it makes sense to change that part as well.


Just because a larger number of errors shows up after making a change to your code does not mean that the change was incorrect.

Removing the word "class" from the template instantiation is correct. There must be additional errors in your code that the compiler never got to before because it choked on the "class" error and didn't know how to continue compiling.

Compiler error correction is a very iterative process. Read the error outputs, fix the first few, and recompile. Frequently fixing 1 error will make others go away, too. Sometimes you can identify a handful of errors from the output that are similar to the first error. Fix all of them before recompiling.

As you get more experience, you will better understand what the error messages mean and figure out how many errors you can fix during each iteration.
but that is causing a lot errors so I assume it is not correct


Really? Gosh... it's almost as if I wrote the last line of my post for an actual reason...
You shouldn't need to pass thru that Archive template. There has to be reasonable way to make an object "serializable". You need to do a bit of research on how to use boost::serialze.

In my view, boost::serializable is a waste of time. It's much easier to serialize using the standard iostreams.

Also, boost::serialize creates a binary stream, which is a pain. It's almost always better to serialize to text.
http://www.catb.org/esr/writings/taoup/html/ch01s06.html#id2877684
Last edited on
Thanks doug4 for the insight. The errors are partly on this post and the rest on the next. kbw, I need to use binary because the .txt files would be too big. If the serialization using iostreams is really that much easier, I'd be interested in it. I'm going to read more on it.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
virtuell_funk_seri.cpp: In function ‘int main()’:
virtuell_funk_seri.cpp:100:8: error: ‘Archive’ was not declared in this scope
   Audi<Archive>* a = new Audi<Archive>;
        ^~~~~~~
virtuell_funk_seri.cpp:100:15: error: template argument 1 is invalid
   Audi<Archive>* a = new Audi<Archive>;
               ^
virtuell_funk_seri.cpp:100:31: error: the value of ‘Archive’ is not usable in a constant expression
   Audi<Archive>* a = new Audi<Archive>;
                               ^~~~~~~
virtuell_funk_seri.cpp:100:8: note: ‘Archive’ was not declared ‘constexpr’
   Audi<Archive>* a = new Audi<Archive>;
        ^~~~~~~
virtuell_funk_seri.cpp:100:38: error: type/value mismatch at argument 1 in template parameter list fortemplate<class Archive> class Audi’
   Audi<Archive>* a = new Audi<Archive>;
                                      ^
virtuell_funk_seri.cpp:100:38: note:   expected a type, got ‘Archive’
virtuell_funk_seri.cpp:101:11: error: the value of ‘Archive’ is not usable in a constant expression
   Porsche<Archive>* b = new Porsche<Archive>;
           ^~~~~~~
virtuell_funk_seri.cpp:100:8: note: ‘Archive’ was not declared ‘constexpr’
   Audi<Archive>* a = new Audi<Archive>;
        ^~~~~~~
virtuell_funk_seri.cpp:101:18: error: type/value mismatch at argument 1 in template parameter list fortemplate<class Archive> class Porsche’
   Porsche<Archive>* b = new Porsche<Archive>;
                  ^
virtuell_funk_seri.cpp:101:18: note:   expected a type, got ‘Archive’
virtuell_funk_seri.cpp:101:37: error: the value of ‘Archive’ is not usable in a constant expression
   Porsche<Archive>* b = new Porsche<Archive>;
                                     ^~~~~~~
virtuell_funk_seri.cpp:100:8: note: ‘Archive’ was not declared ‘constexpr’
   Audi<Archive>* a = new Audi<Archive>;
        ^~~~~~~
virtuell_funk_seri.cpp:101:44: error: type/value mismatch at argument 1 in template parameter list fortemplate<class Archive> class Porsche’
   Porsche<Archive>* b = new Porsche<Archive>;
                                            ^
virtuell_funk_seri.cpp:101:44: note:   expected a type, got ‘Archive’
virtuell_funk_seri.cpp:102:6: error: request for member ‘getInfo’ in ‘* a’, which is of non-class type ‘int’
   a->getInfo();
      ^~~~~~~
virtuell_funk_seri.cpp:103:6: error: request for member ‘getInfo’ in ‘* b’, which is of non-class type ‘int’
   b->getInfo();
      ^~~~~~~
virtuell_funk_seri.cpp:104:6: error: request for member ‘A’ in ‘* a’, which is of non-class type ‘int’
   a->A = arma::randu<arma::mat>(4,5);
      ^
virtuell_funk_seri.cpp:105:6: error: request for member ‘A’ in ‘* b’, which is of non-class type ‘int’
   b->A = arma::randu<arma::mat>(6,5);
      ^
virtuell_funk_seri.cpp:106:6: error: request for member ‘x’ in ‘* a’, which is of non-class type ‘int’
   a->x = 20;
      ^
virtuell_funk_seri.cpp:107:6: error: request for member ‘x’ in ‘* b’, which is of non-class type ‘int’
   b->x = 14;
      ^
virtuell_funk_seri.cpp:108:6: error: request for member ‘hp’ in ‘* a’, which is of non-class type ‘int’
   a->hp = 3;
      ^~
virtuell_funk_seri.cpp:109:6: error: request for member ‘owner’ in ‘* b’, which is of non-class type ‘int’
   b->owner = "Joe";
      ^~~~~
virtuell_funk_seri.cpp:125:21: error: template argument 1 is invalid
   Audi<class Archive>* c = new Audi<class Archive>;
                     ^
virtuell_funk_seri.cpp:125:50: error: template argument 1 is invalid
   Audi<class Archive>* c = new Audi<class Archive>;
                                                  ^
virtuell_funk_seri.cpp:126:24: error: template argument 1 is invalid
   Porsche<class Archive>* d = new Porsche<class Archive>;
                        ^
virtuell_funk_seri.cpp:126:56: error: template argument 1 is invalid
   Porsche<class Archive>* d = new Porsche<class Archive>;
                                                        ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
In file included from /usr/include/boost/serialization/split_member.hpp:23:0,
                 from virtuell_funk_seri.cpp:5:
/usr/include/boost/serialization/access.hpp: In instantiation of ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = int]’:
/usr/include/boost/serialization/serialization.hpp:68:22:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = int]’
/usr/include/boost/serialization/serialization.hpp:126:14:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = int]’
/usr/include/boost/archive/detail/oserializer.hpp:149:40:   required from ‘void boost::archive::detail::oserializer<Archive, T>::save_object_data(boost::archive::detail::basic_oarchive&, const void*) const [with Archive = boost::archive::binary_oarchive; T = int]’
/usr/include/boost/archive/detail/oserializer.hpp:102:1:   required from ‘class boost::archive::detail::oserializer<boost::archive::binary_oarchive, int>’
/usr/include/boost/archive/detail/oserializer.hpp:217:31:   required from ‘boost::archive::detail::pointer_oserializer<Archive, T>::pointer_oserializer() [with Archive = boost::archive::binary_oarchive; T = int]’
/usr/include/boost/serialization/singleton.hpp:100:7:   [ skipping 6 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/archive/detail/common_oarchive.hpp:70:22:   required from ‘void boost::archive::detail::common_oarchive<Archive>::save_override(T&) [with T = int* const; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/basic_binary_oarchive.hpp:80:7:   required from ‘void boost::archive::basic_binary_oarchive<Archive>::save_override(const T&) [with T = int*; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/binary_oarchive_impl.hpp:59:9:   required from ‘void boost::archive::binary_oarchive_impl<Archive, Elem, Tr>::save_override(T&) [with T = int* const; Archive = boost::archive::binary_oarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_oarchive.hpp:70:9:   required from ‘Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(const T&) [with T = int*; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/detail/interface_oarchive.hpp:77:32:   required from ‘Archive& boost::archive::detail::interface_oarchive<Archive>::operator&(const T&) [with T = int*; Archive = boost::archive::binary_oarchive]’
virtuell_funk_seri.cpp:117:8:   required from here
/usr/include/boost/serialization/access.hpp:116:11: error: request for member ‘serialize’ in ‘t’, which is of non-class type ‘int’
         t.serialize(ar, file_version);
         ~~^~~~~~~~~
/usr/include/boost/serialization/access.hpp: In instantiation of ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = int]’:
/usr/include/boost/serialization/serialization.hpp:68:22:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = int]’
/usr/include/boost/serialization/serialization.hpp:126:14:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = int]’
/usr/include/boost/archive/detail/iserializer.hpp:188:40:   required from ‘void boost::archive::detail::iserializer<Archive, T>::load_object_data(boost::archive::detail::basic_iarchive&, void*, unsigned int) const [with Archive = boost::archive::binary_iarchive; T = int]’
/usr/include/boost/archive/detail/iserializer.hpp:120:1:   required from ‘class boost::archive::detail::iserializer<boost::archive::binary_iarchive, int>’
/usr/include/boost/archive/detail/iserializer.hpp:369:31:   required from ‘boost::archive::detail::pointer_iserializer<Archive, T>::pointer_iserializer() [with Archive = boost::archive::binary_iarchive; T = int]’
/usr/include/boost/serialization/singleton.hpp:100:7:   [ skipping 7 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/archive/detail/common_iarchive.hpp:66:22:   required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&) [with T = int*; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/basic_binary_iarchive.hpp:75:7:   required from ‘void boost::archive::basic_binary_iarchive<Archive>::load_override(T&) [with T = int*; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/binary_iarchive_impl.hpp:58:9:   required from ‘void boost::archive::binary_iarchive_impl<Archive, Elem, Tr>::load_override(T&) [with T = int*; Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:68:9:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator>>(T&) [with T = int*; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:75:32:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator&(T&) [with T = int*; Archive = boost::archive::binary_iarchive]’
virtuell_funk_seri.cpp:130:8:   required from here
/usr/include/boost/serialization/access.hpp:116:11: error: request for member ‘serialize’ in ‘t’, which is of non-class type ‘int
I've fixed your sample program. I did suggest you look at how to use boost::serialize, but you didn't seem to have made any progress in that area.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <armadillo>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_member.hpp>

#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <vector>

BOOST_SERIALIZATION_ASSUME_ABSTRACT(Car); //Tell Boost that Car is abstract

//Serialization for Armadillo Matrices------------------
BOOST_SERIALIZATION_SPLIT_FREE(arma::mat)
namespace boost::serialization {
    template<class Archive>
    void save(Archive & ar, const arma::mat &t, unsigned int version) {
        ar << t.n_elem;
        auto data = t.colptr(0);
        for (size_t K = 0; K < t.n_elem; ++K)
            ar << data[K];
    }

    template<class Archive>
    void load(Archive & ar, arma::mat &t, unsigned int version) {
        size_t n_elem;
        ar >> n_elem;
        t.set_size(n_elem);
        t.zeros();
        auto data = t.colptr(0);
        for (size_t K = 0; K < n_elem; ++K)
            ar >> data[K];
    }
} // boost::serialization

class Car {
public:
      virtual double getInfo() = 0;

private:
//    template <typename Archive>
//    virtual void serialize(Archive& ar, unsigned int version) = 0;
};

class Porsche : public Car {
public:
    double getInfo() override { return 1.1; }

    template <typename Archive>
    void serialize(Archive& ar, unsigned int) {
        ar & owner;
        ar & hp;
//      ar & A;
    }

public:
    std::string owner;
    int hp{};
//  arma::mat A;
};

class Audi : public Car {
public:
    double getInfo() override { return 2.2; }

    template <typename Archive>
    void serialize(Archive& ar, unsigned int) {
        ar & owner;
        ar & hp;
        ar & second_owner;
        ar & country;
//      ar & A;
    }

public:
    std::string owner;
    int hp{};
    std::string second_owner;
    std::string country;
//  arma::mat A;
};

int main() {
    {
        std::unique_ptr<Audi> audi(new Audi);
        audi->getInfo();
//      audi->A = arma::randu<arma::mat>(4,5);
        audi->hp = 3;

        std::unique_ptr<Porsche> porsche(new Porsche);
        porsche->getInfo();
//      porsche->A = arma::randu<arma::mat>(6,5);
        porsche->hp = 14;
        porsche->owner = "Joe";

        std::ofstream outputStream("bin.dat", std::ios::binary);
//      boost::archive::text_oarchive ss(outputStream);
        boost::archive::binary_oarchive ss(outputStream);
        ss & *audi.get();
        ss & *porsche.get();
    }

    {
        std::unique_ptr<Audi> audi(new Audi);
        std::unique_ptr<Porsche>porsche(new Porsche);

        std::ifstream inputStream("bin.dat", std::ios::binary);
//      boost::archive::text_oarchive ss(outputStream);
        boost::archive::binary_iarchive ss(inputStream);
        ss & *audi.get();
        ss & *porsche.get();

        std::cout << "audi: hp=" << audi->hp << "\n";
        std::cout << "porsche: hp=" << porsche->hp << " owner=" << porsche->owner << "\n";
    }
}


For my own sanity, built with:
 
c++ -std=c++17 -Wall -Wextra x2.cc -o x2 -L/usr/lib/x86_64-linux-gnu -lboost_serialization


There's a reasonable example, with proper support for a base class here:
https://www.boost.org/doc/libs/1_72_0/libs/serialization/doc/tutorial.html
Last edited on
Thanks kbw! Hm so I guess the virtual serialize() in the base class was superfluous...I was hoping to have serialize() as a virtual function within the base class because there will be many more derived classes. So I wanted to have the serialize() be within every derived class so I could call just do something like

1
2
 Audi<class Archive>* a = new Audi<class Archive>;
a->serialize();


Instead of

1
2
3
4
5
6
7
8
9
10
11
12
  Audi<class Archive>* a = new Audi<class Archive>;
  Porsche<class Archive>* b = new Porsche<class Archive>;  
  a->getInfo();
  b->getInfo();  
  a->A = arma::randu<arma::mat>(4,5);
  b->A = arma::randu<arma::mat>(6,5);
  a->x = 20;
  b->x = 14;
  a->hp = 3;
  b->owner = "Joe";
  //a->serialize(); 
  //b->serialize();  


But I think it was all unnecessary because I still need to call for example b-> x = 14;
Last edited on
You wouldn't want to write code like that, you need container support thru polymorphism. What's a more standard use is being able to write code like:
1
2
3
4
5
6
std::vector<Car*> cars;
cars.push_back(new Audi);

std::ofstream os("cars.txt");
for (auto car : cars)
    car->saveOn(os);

or
1
2
3
4
5
std::vector<Car*> cars;

std::ifstream is("cars.txt");
while (is)
    cars.push_back(Car::create(is));
Last edited on
Sorry kbw but I'm not really understanding your code completely. What does car->saveOn(os) do in this case? Meaning, what does this saving into a .txt file help with regard to my last post? Does

cars.push_back(new Audi);

do "essentially" the same as

std::unique_ptr<Audi> audi(new Audi);

in your code above i.e. vector creates a unique pointer for each component in the vector for the class Audi?

Thanks in advance.
Last edited on
You have created an object hierarchy of different kinds of cars. But the only reason you'd do that is to handle them generically.

One of the generic things that you may need is the ability to serialise them; not just Audi or Porche, but any Car. And you'll also want to read them back.

The code above is an example of how you might do that in Code, and the suggestion is that you want to organise your code to support that style of coding.
Thanks kbw. To your code above, I want to define Audi and Porsche as abstract Car classes, not as their own. I'd like this:

1
2
3
4
5
6
7
8
9
10
11
        std::unique_ptr<Car> audi(new Audi);
        audi->getInfo();
        audi->A = arma::randu<arma::mat>(4,5);
        audi->hp = 3;        

        std::unique_ptr<Car> porsche(new Porsche);
        porsche->getInfo();
        porsche->A = arma::randu<arma::mat>(6,5);
        porsche->hp = 14;
        porsche->owner = "Joe";


But I am getting the errors:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

virt_funk_seri.cpp:46:4: error: templates may not be ‘virtualvirtual void serialize(Archive& ar, unsigned int version) = 0;
    ^~~~~~~
virt_funk_seri.cpp:46:64: error: templates may not be ‘virtualvirtual void serialize(Archive& ar, unsigned int version) = 0;
                                                                ^
virt_funk_seri.cpp: In function ‘int main()’:
virt_funk_seri.cpp:91:15: error: ‘class Car’ has no member named ‘A’
         audi->A = arma::randu<arma::mat>(4,5);
               ^
virt_funk_seri.cpp:92:15: error: ‘class Car’ has no member named ‘hp’
         audi->hp = 3;
               ^~
virt_funk_seri.cpp:96:18: error: ‘class Car’ has no member named ‘A’
         porsche->A = arma::randu<arma::mat>(6,5);
                  ^
virt_funk_seri.cpp:97:18: error: ‘class Car’ has no member named ‘hp’
         porsche->hp = 14;
                  ^~
virt_funk_seri.cpp:98:18: error: ‘class Car’ has no member named ‘owner’
         porsche->owner = "Joe";
                  ^~~~~
In file included from /usr/include/boost/serialization/split_member.hpp:23:0,
                 from /usr/include/boost/serialization/nvp.hpp:26,
                 from /usr/include/boost/serialization/array.hpp:19,
                 from /usr/include/boost/archive/basic_binary_iprimitive.hpp:53,
                 from /usr/include/boost/archive/binary_iarchive_impl.hpp:20,
                 from /usr/include/boost/archive/binary_iarchive.hpp:20,
                 from virt_funk_seri.cpp:3:
/usr/include/boost/serialization/access.hpp: In instantiation of ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = Car]’:
/usr/include/boost/serialization/serialization.hpp:68:22:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = Car]’
/usr/include/boost/serialization/serialization.hpp:126:14:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = Car]’
/usr/include/boost/archive/detail/oserializer.hpp:149:40:   required from ‘void boost::archive::detail::oserializer<Archive, T>::save_object_data(boost::archive::detail::basic_oarchive&, const void*) const [with Archive = boost::archive::binary_oarchive; T = Car]’
/usr/include/boost/archive/detail/oserializer.hpp:102:1:   required from ‘class boost::archive::detail::oserializer<boost::archive::binary_oarchive, Car>’
/usr/include/boost/archive/detail/oserializer.hpp:254:13:   required from ‘static void boost::archive::detail::save_non_pointer_type<Archive>::save_standard::invoke(Archive&, const T&) [with T = Car; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/detail/oserializer.hpp:309:22:   [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/archive/detail/common_oarchive.hpp:70:22:   required from ‘void boost::archive::detail::common_oarchive<Archive>::save_override(T&) [with T = const Car; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/basic_binary_oarchive.hpp:80:7:   required from ‘void boost::archive::basic_binary_oarchive<Archive>::save_override(const T&) [with T = Car; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/binary_oarchive_impl.hpp:59:9:   required from ‘void boost::archive::binary_oarchive_impl<Archive, Elem, Tr>::save_override(T&) [with T = const Car; Archive = boost::archive::binary_oarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_oarchive.hpp:70:9:   required from ‘Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(const T&) [with T = Car; Archive = boost::archive::binary_oarchive]’
/usr/include/boost/archive/detail/interface_oarchive.hpp:77:32:   required from ‘Archive& boost::archive::detail::interface_oarchive<Archive>::operator&(const T&) [with T = Car; Archive = boost::archive::binary_oarchive]’
virt_funk_seri.cpp:103:24:   required from here
/usr/include/boost/serialization/access.hpp:116:9: error: ‘void Car::serialize(Archive&, unsigned int) [with Archive = boost::archive::binary_oarchive]’ is private within this context
         t.serialize(ar, file_version);
         ^
virt_funk_seri.cpp:46:17: note: declared private here
    virtual void serialize(Archive& ar, unsigned int version) = 0;



I ran your code with the adjustments above and the adjustment in Car:

1
2
3
4
5
6
7
8
9
class Car {
public:
      virtual double getInfo() = 0;

private:
    template <typename Archive>
    virtual void serialize(Archive& ar, unsigned int version) = 0;
};
Last edited on
To your code above, I want to define Audi and Porsche as abstract Car classes, not as their own. I'd like this:

1
2
3
4
5
6
7
8
9
10
        std::unique_ptr<Car> audi(new Audi);
        audi->getInfo();
        audi->A = arma::randu<arma::mat>(4,5);
        audi->hp = 3;        

        std::unique_ptr<Car> porsche(new Porsche);
        porsche->getInfo();
        porsche->A = arma::randu<arma::mat>(6,5);
        porsche->hp = 14;
        porsche->owner = "Joe";

At line 1 and 6, you still have Audi and Porsche as their own classes - you use new Audi and new Porsche respectively.

You can't instantiate an abstract class. You can only create objects of concrete classes.

From your code, it looks as though what you actually want is just to store the pointers to those objects as base class pointers. Which is fine, but you can only call methods of the base class interface using that pointer. You can't call stuff that's not defined in the Car interface.

The whole point of using a pointer to Car is that you want to use that pointer in a way that's generic to all objects that derive from Car. If you don't, then don't store it as a Car* .
Last edited on
Thanks Mikey. I would like the Audi and Porsche to be defined as Car so the same API could be used. In that sense, could I so something of the sort:

1
2
Audi a;
Car& c = a;


without the unique pointer?
Thanks Mikey. I would like the Audi and Porsche to be defined as Car

But Audi and Porche are classes. Do you mean that you want to delete those classes, and only instantiate objects of type Car?

Or do you mean something else?

In that sense, could I so something of the sort: [...] without the unique pointer?


Yes, you can use a reference instead of a pointer, but it won't change the problem. c is of type Car&, so will only be able to use the interface to Car. You can't use it to access things that are in the interface of Audi.

Again: the reason for storing these things as references/pointers to a generic base class, is to treat them generically as the base class type.

If you want to treat them as the specialised subclass, with the specialised subclass interface, you need to declare them as pointers/references to the specialised subclass.

Last edited on
Sorry Mikey I made a mistake. I'd like something like this:

1
2
  Car* a = new Audi();
  Car* b = new Porsche();
You can do that too, but it still won't fix your problem, because... oh, hell, I've explained it twice already.
I was just clarifying what my intention was. One can still do a static cast but the only function that'll be used is the serialize() function from Cars.
Last edited on
the only function that'll be used is the serialize() function from Cars.


1
2
3
        audi->getInfo();
        audi->A = arma::randu<arma::mat>(4,5);
        audi->hp = 3;        


1
2
3
4
        porsche->getInfo();
        porsche->A = arma::randu<arma::mat>(6,5);
        porsche->hp = 14;
        porsche->owner = "Joe";



I added constructors to the derived classes to resolve that issue. Does anyone know how I can call the variables hp, owner, etc. at the end of the code below?

Also, another issue that is bogging me down is the error that templates may not be virtual. This is well known but the solution is different case-to-case. Does anyone have an idea or tip how I can resolve this issue?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

class Porsche : public Car {
public:
    double getInfo() override { return 1.1; }
    Porsche(std::string owner1, int hp1, arma::mat A1)
        {
        owner = owner1;
        hp = hp1;
        A = A1; 
        
        }
    template <typename Archive>
    void serialize(Archive& ar, unsigned int) {
        ar & owner;
        ar & hp;
        ar & A;
    }

private:
    std::string owner;
    int hp{};
    arma::mat A;
};

class Audi : public Car {
public:
    double getInfo() override { return 2; }
    Audi(std::string owner1, int hp1, std::string second_owner1, std::string country1,  arma::mat A1)
        {
        owner = owner1;
        hp = hp1;
        second_owner = second_owner1; 
        country = country1;
        A = A1; 
        }
 
    template <typename Archive>
    void serialize(Archive& ar, unsigned int) {
        ar & owner;
        ar & hp;
        ar & second_owner;
        ar & country;
        ar & A;
    }

private:
    std::string owner;
    int hp{};
    std::string second_owner;
    std::string country;
    arma::mat A;
};

int main() {
   {
        std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
        audi->getInfo();

        std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
        porsche->getInfo();

        std::ofstream outputStream("bin.dat", std::ios::binary);
//      boost::archive::text_oarchive ss(outputStream);
        boost::archive::binary_oarchive ss(outputStream);
        ss & *audi.get();
        ss & *porsche.get();
    }

    {
        std::unique_ptr<Audi> audi = std::make_unique<Audi>();
        std::unique_ptr<Porsche>porsche = std::make_unique<Porsche>();

        std::ifstream inputStream("bin.dat", std::ios::binary);
//      boost::archive::text_oarchive ss(outputStream);
        boost::archive::binary_iarchive ss(inputStream);
        ss & *audi.get();
        ss & *porsche.get();

        std::cout << "audi: hp=" << audi->hp << "\n";
        std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";

    }
}



From the code at the end:

1
2
3
        std::cout << "audi: hp=" << audi->hp << "\n";
        std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";


I'm getting the erros:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
virt_funk_seri.cpp:136:43: error: ‘int Audi::hp’ is private within this context
         std::cout << "audi: hp=" << audi->hp << "\n";
                                           ^~
virt_funk_seri.cpp:95:12: note: declared private here
     int hp{};
            ^
virt_funk_seri.cpp:137:49: error: ‘int Porsche::hp’ is private within this context
         std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
                                                 ^~
virt_funk_seri.cpp:68:12: note: declared private here
     int hp{};
            ^
virt_funk_seri.cpp:137:76: error: ‘std::__cxx11::string Porsche::owner’ is private within this context
         std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
                                                                            ^~~~~
virt_funk_seri.cpp:67:17: note: declared private here
     std::string owner;
                 ^~~~~
virt_funk_seri.cpp:137:103: error: ‘arma::mat Porsche::A’ is private within this context
         std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
                                                                                                       ^
virt_funk_seri.cpp:69:15: note: declared private here
     arma::mat A;


Erros regarding virtual templates:

1
2
3
4
5
virt_funk_seri.cpp:46:4: error: templates may not be ‘virtualvirtual void serialize(Archive& ar, unsigned int version) = 0;
    ^~~~~~~
virt_funk_seri.cpp:46:64: error: templates may not be ‘virtualvirtual void serialize(Archive& ar, unsigned int version) = 0;


Last edited on
Pages: 1234