#include #include struct not_a_domain { static int const index = 0; static char deduce(...); }; template struct domain : Domain { typedef Domain next_domain; static int const index = Domain::index + 1; static char (&deduce(Domain*))[index]; using Domain::deduce; }; struct default_domain : domain<> {}; template <> struct domain : default_domain {}; char (&default_case(void*, void*))[1]; char (&default_case(default_domain*, void*))[2]; char (&default_case(void*, default_domain*))[3]; char (&default_case(default_domain*, default_domain*))[4]; template struct nth_domain : nth_domain {}; template struct nth_domain<0, Domains> { typedef Domains type; }; template < class D0, class D1, int DefaultCase = sizeof(default_case((D0*)0, (D1*)0)) > struct deduce_common : nth_domain< domain::index - sizeof(domain::deduce((D1*)0)), D0 > {}; template struct deduce_common { typedef D1 type; }; template struct deduce_common { typedef D0 type; }; template <> struct deduce_common { typedef default_domain type; }; template struct deduce_common { typedef D0 type; }; template struct deduce_common { typedef D1 type; }; template struct deduce_domain3 : deduce_common::type> {}; struct D0 : domain<> { }; struct D1 : domain // a sub-domain of D0 { }; struct D2 : domain // a sub-domain of D0 { }; struct D3 : domain<> { }; struct DD0 : domain // a sub-domain of default_domain { }; struct DD1 : domain // a sub-domain of default_domain { }; struct DD2 : domain // a sub-domain of default_domain { }; struct DD3 : domain // a sub-domain of DD2 { }; int main() { using boost::is_same; BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, default_domain>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, DD0>)); BOOST_MPL_ASSERT((is_same::type, DD0>)); BOOST_MPL_ASSERT((is_same::type, DD0>)); BOOST_MPL_ASSERT((is_same::type, DD0>)); BOOST_MPL_ASSERT((is_same::type, DD0>)); BOOST_MPL_ASSERT((is_same::type, DD0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D1>)); // Very tricky to get right BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D0>)); BOOST_MPL_ASSERT((is_same::type, D1>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, DD2>)); BOOST_MPL_ASSERT((is_same::type, DD2>)); BOOST_MPL_ASSERT((is_same::type, DD2>)); // These should be ambiguous. BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); BOOST_MPL_ASSERT((is_same::type, not_a_domain>)); }