Are there still good reasons to use chainned base cases rather than a flat multiple inheritance?
It used to be the case that some classes were designed to be inherted in chain. I think this was to force the empty base class optimization. I understand this is how Boost.Operators were designed.
struct empty{};
template<class Base = empty>
struct A : Base{};
template<class Base = empty>
struct B : Base{};
template<class Base = empty>
struct C : Base{};
struct S : A<B<C<>>>{};
int main(){static_assert(sizeof(S)==1, "!");}
Is this necessary anymore in new compilers (today is 2019), or I can ditch all that complexity and live with normal inheritance?
struct A{};
struct B{};
struct C{};
struct S : A, B, C{};
int main(){static_assert( sizeof(S) == 1 , "!");}
does it serve any primary or secondary purpose anymore?
The standard states in [class.derived]/7
that:
A base class subobject may be of zero size.
This means that EBO is not mandatory for compilers to implement. However nearly all compilers implement it.
From C++20 onwards, there is the [[no_unique_address]]
attribute which can be applied to the empty member subobjects:
The empty member subobjects are permitted to be optimized out just like the empty bases if they use the attribute
[[no_unique_address]]
. Taking the address of such member results in an address that may equal the address of some other member of the same object.