    //
    //  main.cpp
    //  TestConstness
    //
    //  Created by Marco Antognini on 27/10/13.
    //  Copyright (c) 2013 Marco Antognini. All rights reserved.
    //

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

    class X {
        int x;
    public:
        X(int y) : x(y) { }
        void print() const { std::cout << "X::" << x << std::endl; }
        void foo() { ++x; }
    };

    using XPtr = std::shared_ptr<X>;
    using ConstXPtr = std::shared_ptr<X const>;

    XPtr createX(int x) { return std::make_shared<X>(x); }

    void goo(XPtr p) {
        p->print();
        p->foo();
        p->print();
    }

    void hoo(ConstXPtr p) {
        p->print();
    //    p->foo(); // ERROR :-)
    }

    using XsPtr = std::vector<XPtr>;
    using ConstXsPtr = std::vector<ConstXPtr>;

    void ioo(ConstXsPtr xs) {
        for (auto p : xs) {
            p->print();
    //        p->foo(); // ERROR :-)
        }
    }

    ConstXsPtr toConst(XsPtr xs) {
        ConstXsPtr cxs(xs.size());
        std::copy(std::begin(xs), std::end(xs), std::begin(cxs));
        return cxs;
    }

    void joo(XsPtr xs) {
        for (auto p: xs) {
            p->foo();
        }
    }

    // ERROR :-)
    //XsPtr toNonConst(ConstXsPtr cxs) {
    //    XsPtr xs(cxs.size());
    //    std::copy(std::begin(cxs), std::end(cxs), std::begin(xs));
    //    return xs;
    //}

    class E {
        XsPtr xs;
    public:
        E() {
            for (auto i : { 2, 3, 5, 7, 11, 13 }) {
                xs.emplace_back(createX(std::move(i)));
            }
        }

        void loo() {
            std::cout << "\n\nloo()" << std::endl;
            ioo(toConst(xs));

            joo(xs);

            ioo(toConst(xs));
        }

        void moo() const {
            std::cout << "\n\nmoo()" << std::endl;
            ioo(toConst(xs));

            joo(xs); // Should not be allowed

            ioo(toConst(xs));
        }
    };

    int main(int argc, const char * argv[])
    {
        std::cout << "Hello, World!\n";

        XPtr p = createX(42);

        goo(p);
        hoo(p);

        E e;
        e.loo();
        e.moo();

        // WORKS!

        return 0;
    }

