There is a simple way and the best way to solve this problem.
The simplest solution is to simply use a compilation type selector of type conditional_t ββin combination with a class with an empty base:
template <int M> struct empty_base {}; template <int flags> struct Foo : std::conditional_t<flags & Has_A, A, empty_base<1>> , std::conditional_t<flags & Has_B, B, empty_base<2>> , std::conditional_t<flags & Has_C, C, empty_base<3>> { int x; };
The problem with this approach is that it will not be able to start empty optimization of the base class in C ++, due to the use of multiple inheritance. As a result, the values ββof Foo will be one word more than necessary.
You can solve this by linking the databases like this boost.compressed_pair :
template <class T1, class T2> struct compressed_pair_of_bases: T1, T2 {}; template <class T1, int N> struct compressed_pair_of_bases<T1, empty_base<N>>: T1 {}; template <bool Predicate, class T, class Next> using predicated_parent_chain_t = typename std::conditional_t<Predicate, compressed_pair_of_bases<T, Next>, Next>; template <int flags> struct Bar : predicated_parent_chain_t<!!(flags & Has_A), A, predicated_parent_chain_t<!!(flags & Has_B), B, predicated_parent_chain_t<!!(flags & Has_C), C, empty_base<1>>>> { int x; };
This solution allows you to fully optimize the basic types if they are not selected:
std::cout << sizeof(Bar<0>);