[serialize] using virtual inheritance causes compiler error

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

[serialize] using virtual inheritance causes compiler error

Douwe Gelling
Hi all,

When trying to serialize a class with a virtual base class, I'm getting compilation errors. It seems to be part of a bug in type_traits, but I'm wondering if anyone knows a workaround for making it work anyhow.

ultimately, the error boils down to "error: virtual function 'A::foo' has more than one final overrider in 'boost_type_traits_internal_struct_X'", using the code listing below..
It's simplified as much as possible, but obviously I need virtual inheritance due to using diamond inheritance.


#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/serialization.hpp>

struct A
{
  virtual ~A(){};
  virtual void foo() = 0;
  template <class Archive>
  void serialize(Archive& ar, const unsigned int version)
  {
  }
};

struct B : public virtual A
{
  virtual void foo()
  {
  }
  template <class Archive>
  void serialize(Archive& ar, const unsigned int version)
  {
    ar& boost::serialization::base_object<A>(*this);
  }
};

struct C : public B
{
  template <class Archive>
  void serialize(Archive& ar, const unsigned int version)
  {
    ar& boost::serialization::base_object<B>(*this);
  }
};

BOOST_CLASS_EXPORT(C);

int main()
{
  C c;
  return 0;
}

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [serialize] using virtual inheritance causes compiler error

Robert Ramey
On 10/26/16 8:45 AM, Douwe Gelling wrote:

> Hi all,
>
> When trying to serialize a class with a virtual base class, I'm getting
> compilation errors. It seems to be part of a bug in type_traits, but I'm
> wondering if anyone knows a workaround for making it work anyhow.
>
> ultimately, the error boils down to "error: virtual function 'A::foo'
> has more than one final overrider in
> 'boost_type_traits_internal_struct_X'", using the code listing below..
> It's simplified as much as possible, but obviously I need virtual
> inheritance due to using diamond inheritance.
>
>
> #include <boost/archive/text_oarchive.hpp>
> #include <boost/serialization/base_object.hpp>
> #include <boost/serialization/export.hpp>
> #include <boost/serialization/serialization.hpp>
>
> struct A
> {
>   virtual ~A(){};
>   virtual void foo() = 0;
>   template <class Archive>
>   void serialize(Archive& ar, const unsigned int version)
>   {
>   }
> };
>
> struct B : public virtual A
> {
>   virtual void foo()
>   {
>   }
>   template <class Archive>
>   void serialize(Archive& ar, const unsigned int version)
>   {
>     ar& boost::serialization::base_object<A>(*this);
>   }
> };
>
> struct C : public B
> {
>   template <class Archive>
>   void serialize(Archive& ar, const unsigned int version)
>   {
>     ar& boost::serialization::base_object<B>(*this);
>   }
> };
>
> BOOST_CLASS_EXPORT(C);
>
> int main()
> {
>   C c;
>   return 0;
> }
>

Just some quick observations:

a) there is a example/test for diamond inheritance in the test suite
b) I don't see diamond inhertance in your example.
c) I might be helpful to indicate the compiler
d) Your not actually doing an serialization so I doubt you need "export"

I would keep cutting down the example until it starts to compile.  I'm
very doubtful that this has anything to do with serialization or diamond
inheritance

Robert Ramey


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [serialize] using virtual inheritance causes compiler error

Douwe Gelling
Yes, I've removed everything unnecessary to make the error show up, to not confound the problem.

a) yes, but it doesn't declare a member function and then implement it in the middle of the diamond
b) In my actual code, I'm using diamond inheritance of course, but it's not needed to make the code fail to compile.
c) It fails to compile on both apple LLVM 8.0.0 on osx, and on gcc 4.9 on ubuntu 12.04
d) not in the example, but in my project I need it to actually export. Removing the export makes the code compile, but that doesn't help me, since I want to do serialization

Note that I don't actually need to instantiate anything. I can remove `int main` entirely, and only compile an object file and it generates the same error.

To make the code compile, I can do multiple things: remove the text_oarchive include, remove the export directive, remove the virtual inheritance for `struct B`, remove the implementation of `void foo`, remove the serialization of base_object<B> from struct C...

 That makes the example compile, but doesn't tell me how to serialize an object with diamond inheritance, where a pure virtual method from the virtual base class is implemented by one of the classes in the middle.




On Thu, Oct 27, 2016 at 3:22 AM Robert Ramey <[hidden email]> wrote:
On 10/26/16 8:45 AM, Douwe Gelling wrote:
> Hi all,
>
> When trying to serialize a class with a virtual base class, I'm getting
> compilation errors. It seems to be part of a bug in type_traits, but I'm
> wondering if anyone knows a workaround for making it work anyhow.
>
> ultimately, the error boils down to "error: virtual function 'A::foo'
> has more than one final overrider in
> 'boost_type_traits_internal_struct_X'", using the code listing below..
> It's simplified as much as possible, but obviously I need virtual
> inheritance due to using diamond inheritance.
>
>
> #include <boost/archive/text_oarchive.hpp>
> #include <boost/serialization/base_object.hpp>
> #include <boost/serialization/export.hpp>
> #include <boost/serialization/serialization.hpp>
>
> struct A
> {
>   virtual ~A(){};
>   virtual void foo() = 0;
>   template <class Archive>
>   void serialize(Archive& ar, const unsigned int version)
>   {
>   }
> };
>
> struct B : public virtual A
> {
>   virtual void foo()
>   {
>   }
>   template <class Archive>
>   void serialize(Archive& ar, const unsigned int version)
>   {
>     ar& boost::serialization::base_object<A>(*this);
>   }
> };
>
> struct C : public B
> {
>   template <class Archive>
>   void serialize(Archive& ar, const unsigned int version)
>   {
>     ar& boost::serialization::base_object<B>(*this);
>   }
> };
>
> BOOST_CLASS_EXPORT(C);
>
> int main()
> {
>   C c;
>   return 0;
> }
>

Just some quick observations:

a) there is a example/test for diamond inheritance in the test suite
b) I don't see diamond inhertance in your example.
c) I might be helpful to indicate the compiler
d) Your not actually doing an serialization so I doubt you need "export"

I would keep cutting down the example until it starts to compile.  I'm
very doubtful that this has anything to do with serialization or diamond
inheritance

Robert Ramey


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [serialize] using virtual inheritance causes compiler error

Gavin Lambert
On 28/10/2016 00:17, Douwe Gelling wrote:
> c) It fails to compile on both apple LLVM 8.0.0 on osx, and on gcc 4.9
> on ubuntu 12.04

It compiles in VS2013...

>  That makes the example compile, but doesn't tell me how to serialize an
> object with diamond inheritance, where a pure virtual method from the
> virtual base class is implemented by one of the classes in the middle.

On occasion with diamond inheritance it can help to explicitly instruct
the compiler which "path" to take by further overriding the method in
the class that rejoins the diamond.  It's possible this may help with
your issue as well.

eg:

struct A
{
     virtual void act() = 0;
};

struct B1 : public virtual A
{
};

struct B2 : public virtual A
{
     virtual void act() override { ... }
};

struct C : public B1, public B2
{
     // explicitly delegate to one of the bases
     virtual void act() override { B2::act(); }
};


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

[Serialize] master build failed due to friend template

alainm
In reply to this post by Robert Ramey

  Hi Robert,

My build is currently failing on master due to the following friend
declaration in array.hpp:
[...]
public:
     // note: I would like to make the copy constructor private but this
breaks
     // make_array.  So I try to make make_array a friend - but that
doesn't
     // build.  Need a C++ guru to explain this!
     template<class S>
     friend const boost::serialization::array_wrapper<T> make_array( T*
t, S s);
[...]
actual definition:

template<class T, class S>
inline
const array_wrapper< T > make_array( T* t, S s){
     const array_wrapper< T > a(t, s);
     return a;
}

the problem is that the actual template definition takes two template
parameters.
Has a result, the friend declaration introduces a new template that will
be missing at link time.

I'd like to have it fixed for the upcomming release so that we could
merge in a long overdue update of the MPI lib.
The fix seems kind of trivial:
https://github.com/boostorg/serialization/pull/46

I also have an issue with the selection criteria for emplace_hint which
fails (at least) on intel C++/CentOS 6.5:
https://github.com/boostorg/serialization/pull/47

Regards

Alain

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [serialize] using virtual inheritance causes compiler error

Boost - Users mailing list
In reply to this post by Gavin Lambert
(sorry for the extremely late reply, I just came across this issue again and realised I never did)

It's good that it works in vs2013, but does this mean it ought to compile anywhere and this is a bug though, or that vs2013 is just a fluke?

Your suggestion to override explicitly didn't help in my case unfortunately. It seems to actually be a problem in Boost.TypeTraits, I've commented on a similar issue there (see: https://svn.boost.org/trac/boost/ticket/11323), but it's impacting the use of serialization. Naively, I would expect the example code to compile when using one of boost.Serialize's examples and merely overriding a base function, but it breaks. It feels to me like a bug of some sort, would people here agree?

On Fri, Oct 28, 2016 at 12:36 AM Gavin Lambert <[hidden email]> wrote:
On 28/10/2016 00:17, Douwe Gelling wrote:
> c) It fails to compile on both apple LLVM 8.0.0 on osx, and on gcc 4.9
> on ubuntu 12.04

It compiles in VS2013...

>  That makes the example compile, but doesn't tell me how to serialize an
> object with diamond inheritance, where a pure virtual method from the
> virtual base class is implemented by one of the classes in the middle.

On occasion with diamond inheritance it can help to explicitly instruct
the compiler which "path" to take by further overriding the method in
the class that rejoins the diamond.  It's possible this may help with
your issue as well.

eg:

struct A
{
     virtual void act() = 0;
};

struct B1 : public virtual A
{
};

struct B2 : public virtual A
{
     virtual void act() override { ... }
};

struct C : public B1, public B2
{
     // explicitly delegate to one of the bases
     virtual void act() override { B2::act(); }
};


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [Serialize] master build failed due to friend template

Boost - Users mailing list
In reply to this post by alainm
On 10/28/16 6:19 AM, alainm wrote:

>
>  Hi Robert,
>
> My build is currently failing on master due to the following friend
> declaration in array.hpp:
> [...]
> public:
>     // note: I would like to make the copy constructor private but this
> breaks
>     // make_array.  So I try to make make_array a friend - but that doesn't
>     // build.  Need a C++ guru to explain this!
>     template<class S>
>     friend const boost::serialization::array_wrapper<T> make_array( T*
> t, S s);
> [...]
> actual definition:
>
> template<class T, class S>
> inline
> const array_wrapper< T > make_array( T* t, S s){
>     const array_wrapper< T > a(t, s);
>     return a;
> }
>
> the problem is that the actual template definition takes two template
> parameters.
> Has a result, the friend declaration introduces a new template that will
> be missing at link time.
>
> I'd like to have it fixed for the upcomming release so that we could
> merge in a long overdue update of the MPI lib.
> The fix seems kind of trivial:
> https://github.com/boostorg/serialization/pull/46
>
> I also have an issue with the selection criteria for emplace_hint which
> fails (at least) on intel C++/CentOS 6.5:
> https://github.com/boostorg/serialization/pull/47
>
> Regards
>
> Alain

I'm looking at my copies of develop and master branches and it seems to
me that this is fixed.

https://github.com/boostorg/serialization/blob/develop/include/boost/serialization/array_wrapper.hpp

Robert Ramey
_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [Serialize] master build failed due to friend template

Boost - Users mailing list
In reply to this post by alainm
On 10/28/16 6:19 AM, alainm wrote:

>
>  Hi Robert,
>
> My build is currently failing on master due to the following friend
> declaration in array.hpp:
> [...]
> public:
>     // note: I would like to make the copy constructor private but this
> breaks
>     // make_array.  So I try to make make_array a friend - but that doesn't
>     // build.  Need a C++ guru to explain this!
>     template<class S>
>     friend const boost::serialization::array_wrapper<T> make_array( T*
> t, S s);
> [...]
> actual definition:
>
> template<class T, class S>
> inline
> const array_wrapper< T > make_array( T* t, S s){
>     const array_wrapper< T > a(t, s);
>     return a;
> }
>
> the problem is that the actual template definition takes two template
> parameters.
> Has a result, the friend declaration introduces a new template that will
> be missing at link time.
>
> I'd like to have it fixed for the upcomming release so that we could
> merge in a long overdue update of the MPI lib.
> The fix seems kind of trivial:
> https://github.com/boostorg/serialization/pull/46
>
> I also have an issue with the selection criteria for emplace_hint which
> fails (at least) on intel C++/CentOS 6.5:
> https://github.com/boostorg/serialization/pull/47

These are both fixed in develop and master.  I update the code on my
machine and checked it in sometime ago rather than doing the pr merge.

>
> Regards
>
> Alain

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users