// From Erik Berdahl's presentation, Classes that Work.

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

class RandomObject {};
class TypeErasure;

typedef std::vector<TypeErasure> Document;

template <typename T> void print(const T& x);
void print(const RandomObject& d);
void print(const TypeErasure& x);
void print(const Document& d);

// TypeErasure is a concrete non-templated class which
// holds any type conforming to a given interface.
class TypeErasure {
private:
    // Concept is an abstract base class corresponding
    // to the interface being enforced. Note that this
    // class can't be templated on the stored type since
    // it would require that the TypeEreasure class be
    // also templated on the stored type, i.e. the impl
    // pointer would need to be templated.
    struct Concept {
        // Use a virtual destructor since the Model<T>
        // will be deleted through the Concept class.
        virtual ~Concept() {}
        virtual Concept* copy() const = 0;
        // Forwarding common interface functions to the
        // stored type.
        virtual void print() const = 0;
    };

    // Model<T> is an aggregate which adapts the interface
    // (if necessary) and holds the stored data of type T.
    template <typename T>
    struct Model: Concept {
        explicit Model(const T& x) :
            data(x) {
        }
        Concept* copy() const {
            return new Model(data);
        }
        void print() const {
            // Use of the external namespace operator "::" to
            // tell the compiler to look for the print function
            // in the outer namespace, i.e. outside of Model<T>.
            ::print(data);
        }

        T data;	// Must have a print(data) defined somewhere.
    };

    // The impl member is a pointer to the instantiated Model<T>.
    // See the private implementation pattern for references on this.
    // Note that the impl pointer isn't templated. If it was, the
    // TypeErasure class would also require to be templated.
    Concept* impl;

public:
    // Constructor which takes any type T whose interface matches
    // the one enforced by Model<T>. Could include fundamental types.
    // The constructor is declared explicit to prevents it from
    // being invoked implicitly as a conversion.
    template <typename T>
    explicit TypeErasure(const T& x) :
        impl(new Model<T> (x)) {
    }
    ~TypeErasure() {
        delete impl;
    }

    // TypeErasure copy constructor is implemented by
    // copying the stored object behind the scene.
    TypeErasure(const TypeErasure& x) :
        impl(x.impl->copy()) {
    }

    // Pass by value for exception safety and
    // to allow compiler's optimizations.
    TypeErasure& operator=(TypeErasure x) {
        swap(*this, x);
        return *this;
    }

    friend void swap(TypeErasure& x, TypeErasure& y) {
        std::swap(x.impl, y.impl);
    }

    friend void print(const TypeErasure& x);
};

template <typename T>
void print(const T& x) {
    std::cout << x << std::endl;
}

void print(const RandomObject& d) {
    std::cout << "RandomObject" << std::endl;
}

void print(const TypeErasure& x) {
    x.impl->print();
}

void print(const Document& d) {
    std::cout << "<document>" << std::endl;
    // Go over document's objects, calling print on each one.
    std::for_each(d.begin(), d.end(),
            std::ptr_fun<const TypeErasure&, void>(print));
    std::cout << "</document>" << std::endl;
}

int main() {
    Document doc;
    doc.push_back(TypeErasure(RandomObject()));
    doc.push_back(TypeErasure(std::string("Cow !")));
    doc.push_back(TypeErasure(doc));
    doc.push_back(TypeErasure(1927));
    std::for_each(doc.begin(), doc.end(),
            std::ptr_fun<const TypeErasure&, void>(print));
    return 0;
}