Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

libs/type_erasure/example/associated.cpp

// Boost.TypeErasure library
//
// Copyright 2012 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: associated.cpp 79777 2012-07-28 03:43:26Z steven_watanabe $

#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/deduced.hpp>
#include <boost/type_erasure/same_type.hpp>
#include <boost/pointee.hpp>
#include <boost/mpl/vector.hpp>
#include <iostream>

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

//[associated1
/*`
    Associated types are defined using the __deduced
    template.  __deduced is just like an ordinary
    placeholder, except that the type that it binds
    to is determined by calling a metafunction and
    does not need to be specified explicitly.

    For example, we can define a concept for
    holding any iterator, raw pointer, or
    smart pointer as follows.

    Note the extra trickery to make sure that it is safe
    to instantiate pointee with a placeholder, because
    argument dependant lookup can cause spurious instantiations.
*/

template<class T>
struct pointee
{
    typedef typename mpl::eval_if<is_placeholder<T>,
        mpl::identity<void>,
        boost::pointee<T>
    >::type type;
};

template<class T = _self>
struct pointer :
    mpl::vector<
        copy_constructible<T>,
        dereferenceable<deduced<pointee<T> >&, T>
    >
{
    // provide a typedef for convenience
    typedef deduced<pointee<T> > element_type;
};

//]

void associated2() {
    //[associated2
    /*`
        Now the Concept of `x` uses two placeholders, `_self`
        and `pointer<>::element_type`.  When we construct `x`,
        with an `int*`, `pointer<>::element_type` is deduced
        as `pointee<int*>::type` which is `int`.  Thus, dereferencing
        `x` returns an __any that contains an `int`.
    */
    int i = 10;
    any<
        mpl::vector<
            pointer<>,
            typeid_<pointer<>::element_type>
        >
    > x(&i);
    int j = any_cast<int>(*x); // j == i
    //]
}

void associated3() {
    //[associated3
    /*`
        Sometimes we want to require that the associated
        type be a specific type.  This can be solved using
        the __same_type concept.  Here we create an any that
        can hold any pointer whose element type is `int`.
    */
    int i = 10;
    any<
        mpl::vector<
            pointer<>,
            same_type<pointer<>::element_type, int>
        >
    > x(&i);
    std::cout << *x << std::endl; // prints 10
    /*`
        Using __same_type like this effectively causes the library to
        replace all uses of `pointer<>::element_type` with `int`
        and validate that it is always bound to `int`.
        Thus, dereferencing `x` now returns an `int`.
    */
    //]
}

void associated4() {
    //[associated4
    /*`
        __same_type can also be used for two placeholders.
        This allows us to use a simple name instead of
        writing out an associated type over and over.
    */
    int i = 10;
    any<
        mpl::vector<
            pointer<>,
            same_type<pointer<>::element_type, _a>,
            typeid_<_a>,
            copy_constructible<_a>,
            addable<_a>,
            ostreamable<std::ostream, _a>
        >
    > x(&i);
    std::cout << (*x + *x) << std::endl; // prints 20
    //]
}

//[associated
//` (For the source of the examples in this section see
//` [@boost:/libs/type_erasure/example/associated.cpp associated.cpp])
//` [associated1]
//` [associated2]
//` [associated3]
//` [associated4]
//]