/*
(c) 2013 +++ Filip Stoklas, aka FipS, http://w...content-available-to-author-only...S.com +++
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
ARTICLE URL: http://f...content-available-to-author-only...s.com/viewtopic.php?f=3&t=1194
*/

#include <iostream>
#include <vector>
#include <memory>
#include <utility>

struct dbgVectorPairInt : std::vector<std::pair<int,int>>
{
    dbgVectorPairInt() { std::cout << "dbgVectorPairInt::dbgVectorPairInt()" << std::endl; }

    dbgVectorPairInt(dbgVectorPairInt const&) { std::cout << "dbgVectorPairInt::dbgVectorPairInt(const&)" << std::endl; }
    
    dbgVectorPairInt(dbgVectorPairInt &&) { std::cout << "dbgVectorPairInt::dbgVectorPairInt(&&)" << std::endl; }

    ~dbgVectorPairInt() { std::cout << "dbgVectorPairInt::~dbgVectorPairInt()" << std::endl; }
};

struct Circle
{
    void draw(std::ostream &out) { out << "Circle::draw()\n"; }
};

struct Square
{
    void draw(std::ostream &out) { out << "Square::draw()\n"; }
};

struct Polygon
{
    void draw(std::ostream &out) { out << "Polygon::draw()\n"; }
    dbgVectorPairInt vertices;
};

struct List
{
    template <typename Shape_T>
    void push(Shape_T shape)
    {
        _shapes.emplace_back(If_ptr(new Slot<Shape_T>(shape)));
    }

    void draw(std::ostream &out)
    {
        for(auto &shape : _shapes)
        {
            shape->draw(out);
        }
    }

 private:

    struct If
    {
        virtual void draw(std::ostream &out) = 0;
    };

    template <typename Shape_T>
    struct Slot : public If
    {
        virtual void draw(std::ostream &out) { shape.draw(out); }

        Slot(Shape_T shape) : shape(shape) {}
        Shape_T shape;
    };

    typedef std::unique_ptr<If> If_ptr;
    std::vector<If_ptr> _shapes;
};

int main()
{
    Square s;
    Circle c;
    List l;

    Polygon p;

    l.push(s);
    l.push(c);
    l.push(c);
    l.push(c);
    l.push(p);

    l.draw(std::cout);

    return 0;
}

// Compiled under Visual C++ 2012, output:
// Square::draw()
// Circle::draw()
// Circle::draw()
// Circle::draw()