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$
#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 such as `typename T::value_type` or
`typename std::iterator_traits<T>::reference` are
quite common in template programming.
Boost.TypeErasure handles them 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 an iterator, raw pointer, or
smart pointer as follows.
First, we define a metafunction called `pointee`
defining the associated type.
*/
template<class T>
struct pointee
{
typedef typename mpl::eval_if<is_placeholder<T>,
mpl::identity<void>,
boost::pointee<T>
>::type type;
};
/*`
Note that we can't just use `boost::pointee`, because
this metafunction needs to be safe to instantiate
with placeholders. It doesn't matter what it returns
as long as it doesn't give an error. (The library
never tries to instantiate it with a placeholder, but
argument dependent lookup can cause spurious instantiations.)
*/
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]
//]