// Boost.TypeErasure library
//
// Copyright 2011 Steven Watanabe
//
// Distributed under the Boost Software License Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// $Id$

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/concept_interface.hpp>
#include <boost/type_erasure/rebind_any.hpp>
#include <vector>

namespace mpl = boost::mpl;
using namespace boost::type_erasure;

//[custom1
/*`
    Earlier, we used __BOOST_TYPE_ERASURE_MEMBER to define
    a concept for containers that support `push_back`.  Sometimes
    this interface isn't flexible enough, however.  The library
    also provides a lower level interface that gives full
    control of the behavior.  Let's take a look at what we
    would need in order to define `has_push_back.`  First,
    we need to define the `has_push_back` template itself.  We'll
    give it two template parameters, one for the container
    and one for the element type.  This template must have
    a static member function called apply which is used
    to execute the operation.
*/

template<class C, class T>
struct has_push_back
{
    static void apply(C& cont, const T& arg) { cont.push_back(arg); }
};
//]

//[custom3
/*`
    Our second task is to customize __any so that we can call `c.push_back(10)`.
    We do this by specializing __concept_interface.
    The first argument is `has_push_back`, since we want to inject a member
    into every __any that uses the `has_push_back` concept.  The second argument,
    `Base`, is used by the library to chain multiple uses of __concept_interface
    together.  We have to inherit from it publicly.  `Base` is also used
    to get access to the full __any type.  The third argument is the placeholder
    that represents this any.  If someone used `push_back<_c, _b>`,
    we only want to insert a `push_back` member in the container,
    not the value type.  Thus, the third argument is the container
    placeholder.

    When we define `push_back` the argument type uses the metafunction
    __as_param.  This is just to handle the case where `T` is a
    placeholder.  If `T` is not a placeholder, then the metafunction
    just returns its argument, `const T&`, unchanged.
*/
namespace boost {
namespace type_erasure {
template<class C, class T, class Base>
struct concept_interface<has_push_back<C, T>, Base, C> : Base
{
    void push_back(typename as_param<Base, const T&>::type arg)
    { call(has_push_back<C, T>(), *this, arg); }
};
}
}
//]

void custom2() {
    //[custom2
    /*`
        Now, we can use this in an __any using
        __call to dispatch the operation.
    */
    std::vector<int> vec;
    any<has_push_back<_self, int>, _self&> c(vec);
    int i = 10;
    call(has_push_back<_self, int>(), c, i);
    // vec is [10].
    //]
}

void custom4() {
    //[custom4
    /*`
        Our example now becomes
    */
    std::vector<int> vec;
    any<has_push_back<_self, int>, _self&> c(vec);
    c.push_back(10);
    /*`
        which is what we want.
    */
    //]
}

//[custom
//` (For the source of the examples in this section see
//` [@boost:/libs/type_erasure/example/custom.cpp custom.cpp])
//` [custom1]
//` [custom2]
//` [custom3]
//` [custom4]
//]
