#include <iostream>
#include <typeinfo>

template<typename T> struct A {};
template<typename T> struct B1 : virtual A<T> {};
template<typename T> struct B2 : virtual A<T> {};

struct B3 : B1<B3>, B2<B3> { void f() const {std::cout<<"B3::f"<<std::endl;} };

struct C0 {};
struct C1 : B3 {};
struct C2 : B3, A<C2> { void f() const {std::cout<<"C2::f"<<std::endl;B3::f();} };
struct C3 : B1<C3>, B2<C3> { void f() const {std::cout<<"C3::f"<<std::endl;} };

template< typename T>
struct X
{
  static void f(...) {std::cout<<"T("<<typeid(T).name()<<") has no A<U> base"<<std::endl;}

  static void f(T*t,A<T>*) {std::cout<<"T("<<typeid(T).name()<<") has A<T> base"<<std::endl;t->f();}

  template<typename U>
  static void f(T*t,A<U>*) {std::cout<<"T("<<typeid(T).name()<<") has A<U> base with T!=U("<<typeid(T).name()<<")"<<std::endl;t->f();}
};

template<typename T>
void f(T*t)
{
  X<T>::f(t,t);
}

int main()
{
  f((C0*)0);
  f((C1*)0);
  f((C2*)0);
  f((C3*)0);
}
