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

using namespace std;

//  .----------------------------.
//  |         UserConcept        |
//  |                            |
//  '----------------------------'
//                 ^
//                 |
//  .----------------------------.
//  | DefaultConcept<UserConcept>|
//  |                            |
//  '----------------------------'
//                 ^
//                 |
//  .----------------------------.
//  |    UserModel<ValueType>    |
//  |                            |
//  '----------------------------'
//                 ^
//                 |
//  .----------------------------.
//  | DefaultModel<UserConcept,  |
//  |              UserModel>    |
//  '----------------------------'

// Concept default interface. The UserConcept is a pure
// virtual interface corresponding to a user concept.
template<typename UserConcept>
struct DefaultConcept: UserConcept {
    typedef DefaultConcept ConceptType;
    virtual bool equals(const DefaultConcept&) const = 0;
    virtual DefaultConcept* copy() const = 0;
    virtual const std::type_info& type() const = 0;
    virtual ~DefaultConcept() {}
};

// Model default implementation. The UserModel is a
// user supplied model implementation.
template<typename UserModel>
struct DefaultModel: UserModel {
    typedef typename UserModel::ValueType 		ValueType;
    typedef typename UserModel::ConceptType 	ConceptType;

    DefaultModel(const ValueType& value) :
        UserModel(value) /* Call UserModel's constructor. */ {
    }
    bool equals(const ConceptType& other) const {
        // If the other object's type matches ours, and his stored value
        // also matches ours, then we can conclude on the equality.
        return (other.type() == typeid(ValueType))
                && (static_cast<const DefaultModel&>(other).value == this->value);
    }
    DefaultModel* copy() const {
        return new DefaultModel(this->value);
    }
    const std::type_info& type() const {
        return typeid(ValueType);
    }
};

// This is a generic type erasure implementation. The remote
// part is made accessible through overload or the pointer
// operator, i.e. operator ->.
template<typename UserConcept,
         template<class > class UserModel>
class RegularObject {
private:
    typedef DefaultConcept<UserConcept> 	Concept;
    Concept* object;

public:
    template<typename T> explicit RegularObject(const T& x) :
        object(new DefaultModel<UserModel<T> >(x)) {
    }
    RegularObject(const RegularObject& src) :
        object(src.object->copy()) {
    }
    ~RegularObject() {
        delete object;
    }
    RegularObject& operator=(RegularObject rhs) {
        swap(rhs);
        return *this;
    }
    void swap(RegularObject& x) {
        using std::swap;
        swap(object, x.object);
    }
    // Note that when the -> operator is applied to a class instance,
    // it is called as a unary postfix operator; so it is expected
    // to return a value to which the -> operator can again be applied.
    const Concept* operator->() const {
        return object;
    }
    Concept* operator->() {
        return object;
    }
    friend inline bool operator==(const RegularObject& x, const RegularObject& y) {
        return x.object->equals(*y.object);
    }
};

typedef std::pair<int, int> Point;

class Shape {
private:
    // Drawable interface definition. This is our concept.
    struct DrawableConcept {
        virtual void draw(const Point&) const = 0;
    };

    // Drawable interface implementation. This is our model.
    template<typename T>
    struct DrawableModel: DefaultConcept<DrawableConcept> {
        typedef T ValueType;

        DrawableModel(const ValueType& x) :
            value(x) {
        }
        void draw(const Point& where) const {
            value.draw(where);
        }

        ValueType value;
    };

    Point origine;
    RegularObject<DrawableConcept, DrawableModel> object;
public:
    template<typename Drawable>
    Shape(const Point& origine, const Drawable& drawable) :
        origine(origine), object(drawable) {
    }
    void draw() const {
        object->draw(origine);
    }
    Point where() const {
        return origine;
    }
    void move(const Point& to) {
        origine = to;
    }
    inline friend bool operator==(const Shape& x, const Shape& y) {
        return (x.origine == y.origine) && (x.object == y.object);
    }
};

struct Circle {
    Circle(int r) :
        radius(r) {
    }
    void draw(const Point& p) const {
        std::cout << "Shape(Point(" << p.first << ", "
                  << p.second << "), Circle(" << radius << ")); "
                  << std::endl;
    }
    friend inline bool operator==(const Circle& x, const Circle& y) {
        return x.radius == y.radius;
    }
    int radius;
};

struct Rectangle {
    Rectangle(int w, int h) :
        width(w), height(h) {
    }
    void draw(const Point& p) const {
        std::cout << "Shape(Point(" << p.first << ", "
                  << p.second << "), Rectangle(" << width << "x" << height
                  << ")); " << std::endl;
    }
    friend inline bool operator==(const Rectangle& x, const Rectangle& y) {
        return x.width == y.width && x.height == y.height;
    }
    int width;
    int height;
};

struct Text {
    Text(const std::string& text) :
        text(text) {
    }
    void draw(const Point& p) const {
        std::cout << "Shape(Point(" << p.first << ", "
                  << p.second << "), Text(\"" << text
                  << "\")); " << std::endl;
    }
    friend inline bool operator==(const Text& x, const Text& y) {
        return x.text == y.text;
    }
    std::string text;
};

int main() {
    vector<Shape> canvas1;
    canvas1.push_back(Shape(Point(1, 2), Circle(3)));
    canvas1.push_back(Shape(Point(3, 4), Circle(6)));
    canvas1.push_back(Shape(Point(5, 6), Rectangle(9, 10)));
    canvas1.push_back(Shape(Point(7, 8), Text(string("This is a test."))));

    vector<Shape> canvas2(canvas1);

    reverse(canvas1.begin(), canvas1.end());

    find(canvas1.begin(), canvas1.end(), Shape(Point(3, 4), Circle(6)))->move(Point(10, 20));

    for_each(canvas1.begin(), canvas1.end(), mem_fun_ref(&Shape::draw));
    for_each(canvas2.begin(), canvas2.end(), mem_fun_ref(&Shape::draw));

    return 0;
}