// 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/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/tuple.hpp>
#include <boost/mpl/vector.hpp>
#include <iostream>

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

void multi1() {
    //[multi1
    /*`
        Operations can have more than one __any argument.
        Let's use binary addition as an example.
    */
    typedef any<
        mpl::vector<
            copy_constructible<>,
            typeid_<>,
            addable<>,
            ostreamable<>
        >
    > any_type;
    any_type x(10);
    any_type y(7);
    any_type z(x + y);
    std::cout << z << std::endl; // prints 17
    /*`
        This is /not/ a multimethod.  The underlying types of the
        arguments of `+` must be the same or the behavior is undefined.
        This example is correct because the arguments both hold
        `int`'s.

        [note Adding __relaxed leads an exception rather than undefined
        behavior if the argument types are wrong.]
    */
    //]
}

void multi2() {
    //[multi2
    /*`
        __addable`<>` requires the types of the arguments to be exactly
        the same.  This doesn't cover all uses of addition though.  For
        example, pointer arithmetic takes a pointer and an integer and
        returns a pointer.  We can capture this kind of relationship among
        several types by identifying each type involved with a placeholder.
        We'll let the placeholder `_a` represent the pointer and the
        placeholder `_b` represent the integer.
    */

    int array[5];

    typedef mpl::vector<
        copy_constructible<_a>,
        copy_constructible<_b>,
        typeid_<_a>,
        addable<_a, _b, _a>
    > requirements;

    /*`
        Our new concept, `addable<_a, _b, _a>` captures the
        rules of pointer addition: `_a + _b -> _a`.

        Also, we can no longer capture the variables
        independently.
        ``
            any<requirements, _a> ptr(&array[0]); // illegal
        ``
        This doesn't work because the library needs
        to know the type that _b binds to when it
        captures the concept bindings.  We need to
        specify the bindings of both placeholders
        when we construct the __any.
     */

    typedef mpl::map<mpl::pair<_a, int*>, mpl::pair<_b, int> > types; 
    any<requirements, _a> ptr(&array[0], make_binding<types>());
    any<requirements, _b> idx(2, make_binding<types>());
    any<requirements, _a> x(ptr + idx);
    // x now holds array + 2

    /*`
        Now that the arguments of `+` aren't the same type,
        we require that both arguments agree that `_a` maps
        to `int*` and that `_b` maps to `int`.

        We can also use __tuple to avoid having to
        write out the map out explicitly.  __tuple is
        just a convenience class that combines the
        placeholder bindings it gets from all its arguments.
     */
    tuple<requirements, _a, _b> t(&array[0], 2);
    any<requirements, _a> y(get<0>(t) + get<1>(t));
    //]
}


//[multi
//` (For the source of the examples in this section see
//` [@boost:/libs/type_erasure/example/multi.cpp multi.cpp])
//` [multi1]
//` [multi2]
//]
