#include <iostream>
#include <tuple>
#include <type_traits>
using namespace std;

template<typename T>
struct Public : public T
{
	using unspecied_type = T;
};

template<typename T>
struct Private : protected T
{
	using unspecied_type = T;
};

template<typename T>
struct InheritanceSpecifierAdder
{
	using specified_type = Public<T>;
};

template<typename T>
struct InheritanceSpecifierAdder<Private<T>>
{
	using specified_type = Private<T>;
};

template<typename T> 
using AddAccessSpecifier = typename InheritanceSpecifierAdder<T>::specified_type;
	
template<typename... Ts>
class inheriter : public AddAccessSpecifier<Ts>...
{
public:
	using ThisInheriter = inheriter<Ts...>;
};

namespace impl
{
	template<size_t, typename>
	struct inherited_helper;
	
	template<size_t Index, typename... Ts>
	struct inherited_helper<Index, inheriter<Ts...>>
	{
		using type = typename std::tuple_element<Index, std::tuple<Ts...>>::type;
	};
} // namespace impl

template<size_t Index, typename T>
using inherited = typename impl::inherited_helper<Index, typename T::ThisInheriter>::type;

#define KMU_BASE(type) \
	using ThisInheriter = type;

#define THIS_TYPE \
	typename std::remove_reference<typename std::remove_const<decltype(*this)>::type>::type

#define INHERITED(Index) inherited<(Index), THIS_TYPE>

#define SUPER INHERITED(0)
//-----------------------------------------------------------------------------

struct A
{
	KMU_BASE(A);
};

struct B : public inheriter<A>
{};

struct C : public inheriter<A>
{};

struct D : public inheriter<Public<B>, Public<C>>
{};

struct E : public inheriter<Public<B>, Private<C>>
{};

struct F;

#define DBG(X) void f(const X&) { std::cout << #X << "\n"; }
DBG(A);
DBG(B);
DBG(C);
DBG(D);
DBG(E);
DBG(F);

struct F : public inheriter<Private<E>>
{
	F()
	{
		f(SUPER{});
	}
};

//--------------------------------------------------------

int main()
{
	f(inherited<0, D>{});
	f(inherited<1, D>{});
	
	F fff;
	//f(inherited<0, F>{}); // error --> E private
	
	std::cout << "\n" << sizeof(F) << "\n";	
	
	return 0;
}