//======================================================================= // Copyright 2010 Trustees of Indiana University. // Authors: Jeremiah Willcock, Andrew Lumsdaine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #include #include #include #include #include // The usual yes_type/no_type thing; this can be replaced by an MPL version. struct yes_type {char x;}; struct no_type {char x[2];}; BOOST_STATIC_ASSERT(sizeof(yes_type) != sizeof(no_type)); // Base for not_a_domain and default_domain; the special-casing of // default_domain in deduce_domain2 should make sure this is never returned as // a result struct really_not_a_domain { // domain_check acts like a set of ancestor domains (a display in OO terms) // to the current one. The no_type answer says that we hit the ... case (the // first parameter is just so the ... is allowed) and so the thing we're // querying isn't in the set. static no_type domain_check(int, ...) {} // rest is necessary here so the "typename B::rest" recursion doesn't fail, // but it should never be used. typedef void rest; }; struct not_a_domain; // The actual domain class; defaulting to not_a_domain gets the conflict cases // right automatically. template struct domain: public T { // Append T to the set; T** is used to avoid derived-to-base conversions. using T::domain_check; static yes_type domain_check(int, T**) {} typedef T rest; }; // The two base domains. They are incomparable, but anything derived from // default_domain is special-cased in deduce_domain2. struct not_a_domain: domain {}; struct default_domain: domain {}; // The actual least common ancestor code. Walks the ancestors of B, looking // for the closest one that's in A's display (using domain_check). The use of // domain rather than A is so that A itself will be in the set (since a // domain doesn't inherit from anything that contains its own name). template struct deduce_domain2_internal { typedef typename boost::mpl::eval_if_c< sizeof(domain::domain_check(0, (B**)0)) == sizeof(yes_type), boost::mpl::identity, deduce_domain2_internal >::type type; }; // Dispatch on which arguments are derived from default_domain; don't use // mpl::if_ to avoid extra template instantiations. template struct deduce_domain2_cases; template struct deduce_domain2_cases: deduce_domain2_internal {}; template struct deduce_domain2_cases {typedef B type;}; template struct deduce_domain2_cases {typedef A type;}; template struct deduce_domain2_cases: deduce_domain2_internal {}; template struct deduce_domain2: deduce_domain2_cases::value, boost::is_base_and_derived::value> {}; // All of the more-parameter cases should be able to be built just by applying // the two-parameter case repeatedly; deduce_domain2 should be associative as // well. template struct deduce_domain3: deduce_domain2::type, C> {}; // Testing code // Make some domains. struct c_a: domain<> {}; struct c_aa: domain {}; struct c_ab: domain {}; struct c_b: domain<> {}; struct c_ba: domain {}; struct d_a: domain {}; struct d_aa: domain {}; struct d_ab: domain {}; struct d_b: domain {}; // A procedure that does a single test case; the Result** line is to get a // better error message when the types don't match. template void test() { Result **x = (typename deduce_domain2::type**)0; BOOST_STATIC_ASSERT((boost::is_same::type, Result>::value)); } int main(int, char**) { // All of the combinations of pairs of domains test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); d_aa** x = (deduce_domain3::type**)0; d_aa** y = (deduce_domain3::type**)0; d_aa** z = (deduce_domain3::type**)0; return 0; }