The following code aims at providing my library with reflection information about the base classes from which the user's classes derive:
template <class Base1_ = void, class Base2_ = void, class Base3_ = void,
class Base4_ = void>
struct ManagedNode;
// For classes that do not derive
template <> struct ManagedNode<void, void, void, void> {
using Base1 = void; using Base2 = void; using Base3 = void;
using Base4 = void;
};
// To avoid inaccessible base
// See http://stackoverflow.com/q/34255802/2725810
struct Inter0: public ManagedNode<>{};
// For classes that derive from a single base class
template <class Base1_>
struct ManagedNode<Base1_, void, void, void> : public Inter0,
public Base1_ {
using Base1 = Base1_;
};
// To avoid inaccessible base
template <class Base1_>
struct Inter1: public ManagedNode<Base1_>{};
// For classes that derive from two base classes
template <class Base1_, class Base2_>
struct ManagedNode<Base1_, Base2_, void, void> : public Inter1<Base1_>,
public Base2_ {
using Base2 = Base2_;
};
// We can continue in the same manner for 3 and 4 base classes
Here is an example user code:
struct A : public ManagedNode<> {
int data1;
};
struct B : public ManagedNode<> {};
struct C : public ManagedNode<A, B> {};
int main() {
C c;
std::cout << sizeof(c) << std::endl;
return 0;
}
This code produces the output of 12, which means that c
contains the data1
member three times!
I considered using virtual inheritance to avoid this memory overhead. If I simply insert the word virtual
before the word public
for each inheritance, then I get a warning about the base class becoming inaccessible... If I put the word virtual
in every such place besides the declaration of Inter0
, then I get the output of 16 -- worse than before!
I would very much appreciate an explanation of what happens when I use virtual inheritance here.
EDIT: For completeness, here is the version with virtual
inserted (the comment indicates which virtual
needs to be removed for the code to compile):
template <class Base1_ = void, class Base2_ = void, class Base3_ = void,
class Base4_ = void>
struct ManagedNode;
// For classes that do not derive
template <> struct ManagedNode<void, void, void, void> {
using Base1 = void; using Base2 = void; using Base3 = void;
using Base4 = void;
};
// To avoid inaccessible base
// See http://stackoverflow.com/q/34255802/2725810
struct Inter0: virtual public ManagedNode<>{}; // without the word virtual
// in this line, the code compiles
// For classes that derive from a single base class
template <class Base1_>
struct ManagedNode<Base1_, void, void, void> : virtual public Inter0,
virtual public Base1_ {
using Base1 = Base1_;
};
// To avoid inaccessible base
template <class Base1_>
struct Inter1: virtual public ManagedNode<Base1_>{};
// For classes that derive from two base classes
template <class Base1_, class Base2_>
struct ManagedNode<Base1_, Base2_, void, void> : virtual public Inter1<Base1_>,
virtual public Base2_ {
using Base2 = Base2_;
};
// Some user classes for testing the concept
struct A : public ManagedNode<> {
int data1;
};
struct B : public ManagedNode<> {};
struct C : public ManagedNode<A, B> {};
int main() {
C c;
std::cout << sizeof(c) << std::endl;
return 0;
}
Here is the output from the compiler:
temp.cpp: In instantiation of ‘struct ManagedNode<A, void, void, void>’:
temp.cpp:27:8: required from ‘struct Inter1<A>’
temp.cpp:31:8: required from ‘struct ManagedNode<A, B>’
temp.cpp:44:19: required from here
temp.cpp:21:8: error: virtual base ‘ManagedNode<void, void, void, void>’ inaccessible in ‘ManagedNode<A, void, void, void>’ due to ambiguity [-Werror=extra]
struct ManagedNode<Base1_, void, void, void> : virtual public Inter0,
^
temp.cpp: In instantiation of ‘struct Inter1<A>’:
temp.cpp:31:8: required from ‘struct ManagedNode<A, B>’
temp.cpp:44:19: required from here
temp.cpp:27:8: error: virtual base ‘ManagedNode<void, void, void, void>’ inaccessible in ‘Inter1<A>’ due to ambiguity [-Werror=extra]
struct Inter1: virtual public ManagedNode<Base1_>{};
^
temp.cpp: In instantiation of ‘struct ManagedNode<A, B>’:
temp.cpp:44:19: required from here
temp.cpp:31:8: error: virtual base ‘ManagedNode<void, void, void, void>’ inaccessible in ‘ManagedNode<A, B>’ due to ambiguity [-Werror=extra]
struct ManagedNode<Base1_, Base2_, void, void> : virtual public Inter1<Base1_>,
^
temp.cpp:44:8: error: virtual base ‘ManagedNode<void, void, void, void>’ inaccessible in ‘C’ due to ambiguity [-Werror=extra]
struct C : public ManagedNode<A, B> {};
^