Reach C++ policy-based common interface with different template parameters from one container Please review my solution for the following problem. I am interested in:


What do you think of the design
Improvement tips
Usability
Efficiency


Problem: Need to be store policy-based objects with different template parameters in one container, and reach the common interface.

Solution: 
C++ Shell

#include &lt;exception&gt;
#include &lt;iostream&gt;
#include &lt;memory&gt;
#include &lt;string&gt;
#include &lt;vector&gt;

class SinglePolicy
{
public:
    SinglePolicy() = default;

    void push(int data)
    {
        std::cout &lt;&lt; "set to SinglePolicy\n";
        buffer_ = data;
    }

    int pop()
    {
        std::cout &lt;&lt; "return from SinglePolicy\n";
        int data = buffer_;

        buffer_ = -1;

        return data;
    }

protected:
    int buffer_;
};

class VectorPolicy
{
public:
    VectorPolicy() = default;

    virtual void push(int data)
    {
        std::cout &lt;&lt; "emplace_back to VectorPolicy\n";
        buffer_.emplace_back(data);
    }

    virtual int pop()
    {
        std::cout &lt;&lt; "pop front from VectorPolicy\n";
        if(buffer_.empty())
            return -1;

        int data = buffer_[0];
        buffer_.erase(buffer_.begin());

        return data;
    }

protected:
    std::vector&lt;int&gt; buffer_;
};

template&lt;class BufferPolicy&gt;
class PolicyBasedBuffer
        : public BufferPolicy
{
public:
    PolicyBasedBuffer()
        : BufferPolicy()
    {}
};

typedef std::shared_ptr&lt;PolicyBasedBuffer&lt;SinglePolicy&gt;&gt; SinglePolicyPtr;
typedef std::shared_ptr&lt;PolicyBasedBuffer&lt;VectorPolicy&gt;&gt; VectorPolicyPtr;

class PolicyInterface
{
public:
    PolicyInterface(const std::function&lt;void(int)&gt;&amp; pushArg, const std::function&lt;int(void)&gt;&amp; popArg)
        : push(pushArg)
        , pop(popArg)
    {}

    const std::function&lt;void(int)&gt; push;
    const std::function&lt;int(void)&gt; pop;
};

typedef std::shared_ptr&lt;PolicyInterface&gt; PolicyInterfacePtr;

PolicyInterfacePtr saveToPolicyInterface(const SinglePolicyPtr&amp; aPolicy)
{
    return std::make_shared&lt;PolicyInterface&gt;([aPolicy](int data) { aPolicy-&gt;push(data); }, [aPolicy]() { return aPolicy-&gt;pop(); });
}

PolicyInterfacePtr saveToPolicyInterface(const VectorPolicyPtr&amp; aPolicy)
{
    return std::make_shared&lt;PolicyInterface&gt;([aPolicy](int data) { aPolicy-&gt;push(data); }, [aPolicy]() { return aPolicy-&gt;pop(); });
}

int main()
{
    auto singleBuffer = std::make_shared&lt;PolicyBasedBuffer&lt;SinglePolicy&gt;&gt;();
    auto vectorBuffer = std::make_shared&lt;PolicyBasedBuffer&lt;VectorPolicy&gt;&gt;();

    const int seven = 7;

    std::cout &lt;&lt; "PolicyBasedBuffer test:\n";
    singleBuffer-&gt;push(seven);
    if(seven != singleBuffer-&gt;pop())
        throw std::runtime_error("SinglePolicy :: wrong return data");

    vectorBuffer-&gt;push(seven);
    if(seven != vectorBuffer-&gt;pop())
        throw std::runtime_error("VectorPolicy :: wrong return data");

    std::vector&lt;PolicyInterfacePtr&gt; policy;

    policy.push_back(saveToPolicyInterface(std::make_shared&lt;PolicyBasedBuffer&lt;SinglePolicy&gt;&gt;()));
    policy.push_back(saveToPolicyInterface(std::make_shared&lt;PolicyBasedBuffer&lt;VectorPolicy&gt;&gt;()));

    std::cout &lt;&lt; "\nPolicyInterface test:\n";

    for(size_t i=0; i &lt; policy.size(); ++i)
    {
        policy[i]-&gt;push(seven);
        if(seven != policy[i]-&gt;pop())
            throw std::runtime_error("policyInterface :: wrong return data");
    }

    std::cout &lt;&lt; std::flush;
}
Few minor notes.


You have deliberately assigned -1 to represent undef, correct? The question whether you'll ever need to store -1 aside, you should probably define a named constant to get rid of magic number (it also helps when you decide to accept -1s). BTW, the minimal int (-2³¹ or so) is maybe a better alternative.
Every constructor and factory function accepts arguments by const ref. While acceptable for shared_ptr args, it makes sense to accept others (such as closures) by value and then move them inside the object's members.
const_cast is a threat to PolicyInterface's public push and pop methods.
VectorPolicy pushes elements to its right end but pops them on the left. If it should work as a LILO queue, std::deque is a better alternative to std::vector. Otherwise, VectorPolicy should follow stack (LIFO) idiom, and elements popped at the end.