template struct sized_type { typedef char (&type)[N]; }; struct not_a_domain {}; template struct domain { typedef Domain proto_super_domain; }; struct default_domain : domain<> {}; template struct wrap : wrap { typedef Domain type; typedef wrap base; using base::deduce0x; using base::deduce98; static int const index = base::index + 1; static Domain deduce0x(wrap*); static typename sized_type::type deduce98(wrap*); }; template<> struct wrap { typedef not_a_domain type; static int const index = 1; static not_a_domain deduce0x(void*); static sized_type<1>::type deduce98(void*); }; template<> struct wrap : wrap {}; sized_type<1>::type default_case(void*, void*); sized_type<2>::type default_case(wrap*, void*); sized_type<3>::type default_case(void*, wrap*); sized_type<4>::type default_case(wrap*, wrap*); template struct nth_domain : nth_domain {}; template struct nth_domain<0, Wrap> : Wrap {}; template struct nth_domain<1, Wrap> : Wrap::base {}; template < class D0 , class D1 , int DefaultCase = sizeof(default_case((wrap*)0, (wrap*)0)) > struct deduce_common { static int const index = wrap::index - sizeof(wrap::deduce98((wrap*)0)); typedef typename nth_domain >::type type; // the following line does the same as above with decltype // without instantiating unnecessary templates. //typedef decltype(wrap::deduce0x((wrap*)0)) type; }; template struct deduce_common { typedef D1 type; }; template struct deduce_common { typedef D0 type; }; template struct deduce_common { typedef D0 type; }; template struct deduce_common { typedef D1 type; }; template <> struct deduce_common { typedef default_domain type; }; template struct deduce_domain3 { typedef A0 common1; typedef typename deduce_common::type common2; typedef typename deduce_common::type common3; typedef common3 type; }; //////////////////////////////////////////////////// // Begin test code #include #include 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>)); }