// Templates are Complicated
// By Evan Jones 2007-04-17
// http://evanjones.ca/template-conditionals.txt

#include <cstdio>
#include <string>

class A {
public:
    void bar() {
        printf("A::bar()\n");
    }
};

class B {
public:
    virtual void baz() {
        printf("B::baz()\n");
    }
};

class C : public B {
public:
    virtual void baz() {
        printf("C::baz\n");
    }
};

template <typename T> class Wrapper;

template <> class Wrapper<A> {
public:
    void wrapped() {
        printf("Wrapper<A>::wrapped() begin:\n\t");
        contents.bar();
        printf("Wrapper<A>::wrapped() end\n");  
    }

private:
    A contents;
};

template <> class Wrapper<B> {
public:
    void wrapped() {
        printf("Wrapper<B>::wrapped() begin:\n\t");
        contents.baz();
        printf("Wrapper<B>::wrapped() end\n");  
    }

private:
    B contents;
};

struct true_type {};
struct false_type {};

template <typename T, typename SubclassesB> class Wrapper2;

template <typename T> class Wrapper2<T, false_type> {
public:
    void wrapped() {
        printf("Wrapper<T, !(subclasses B)>::wrapped() begin:\n\t");
        contents.bar();
        printf("Wrapper<T, !(subclasses B)>::wrapped() end\n");  
    }

private:
    T contents;
};

template <typename T> class Wrapper2<T, true_type> {
public:
    void wrapped() {
        printf("Wrapper<T, (subclasses B)>::wrapped() begin:\n\t");
        contents.baz();
        printf("Wrapper<T, (subclasses B)>::wrapped() end\n");  
    }

private:
    T contents;
};

int main() {
    A a;
    B b;

    a.bar();
    b.baz();

    Wrapper<A> wrapped_a;
    Wrapper<B> wrapped_b;

    wrapped_a.wrapped();
    wrapped_b.wrapped();

    // Does not work:
    // Wrapper<C> wrapped_c;

    Wrapper2<A, false_type> wrapped_a2;
    Wrapper2<B, true_type> wrapped_b2;

    wrapped_a2.wrapped();
    wrapped_b2.wrapped();
    
    Wrapper2<C, true_type> wrapped_c2;
    wrapped_c2.wrapped();
}

