1 // Boost.TypeErasure library
2 //
3 // Copyright 2011 Steven Watanabe
4 //
5 // Distributed under the Boost Software License Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // $Id$
10 
11 #include <boost/type_erasure/any.hpp>
12 #include <boost/type_erasure/concept_interface.hpp>
13 #include <boost/type_erasure/rebind_any.hpp>
14 #include <vector>
15 
16 namespace mpl = boost::mpl;
17 using namespace boost::type_erasure;
18 
19 //[custom1
20 /*`
21     Earlier, we used __BOOST_TYPE_ERASURE_MEMBER to define
22     a concept for containers that support `push_back`.  Sometimes
23     this interface isn't flexible enough, however.  The library
24     also provides a lower level interface that gives full
25     control of the behavior.  Let's take a look at what we
26     would need in order to define `has_push_back.`  First,
27     we need to define the `has_push_back` template itself.  We'll
28     give it two template parameters, one for the container
29     and one for the element type.  This template must have
30     a static member function called apply which is used
31     to execute the operation.
32 */
33 
34 template<class C, class T>
35 struct has_push_back
36 {
applyhas_push_back37     static void apply(C& cont, const T& arg) { cont.push_back(arg); }
38 };
39 //]
40 
41 //[custom3
42 /*`
43     Our second task is to customize __any so that we can call `c.push_back(10)`.
44     We do this by specializing __concept_interface.
45     The first argument is `has_push_back`, since we want to inject a member
46     into every __any that uses the `has_push_back` concept.  The second argument,
47     `Base`, is used by the library to chain multiple uses of __concept_interface
48     together.  We have to inherit from it publicly.  `Base` is also used
49     to get access to the full __any type.  The third argument is the placeholder
50     that represents this any.  If someone used `push_back<_c, _b>`,
51     we only want to insert a `push_back` member in the container,
52     not the value type.  Thus, the third argument is the container
53     placeholder.
54 
55     When we define `push_back` the argument type uses the metafunction
56     __as_param.  This is just to handle the case where `T` is a
57     placeholder.  If `T` is not a placeholder, then the metafunction
58     just returns its argument, `const T&`, unchanged.
59 */
60 namespace boost {
61 namespace type_erasure {
62 template<class C, class T, class Base>
63 struct concept_interface<has_push_back<C, T>, Base, C> : Base
64 {
push_backboost::type_erasure::concept_interface65     void push_back(typename as_param<Base, const T&>::type arg)
66     { call(has_push_back<C, T>(), *this, arg); }
67 };
68 }
69 }
70 //]
71 
custom2()72 void custom2() {
73     //[custom2
74     /*`
75         Now, we can use this in an __any using
76         __call to dispatch the operation.
77     */
78     std::vector<int> vec;
79     any<has_push_back<_self, int>, _self&> c(vec);
80     int i = 10;
81     call(has_push_back<_self, int>(), c, i);
82     // vec is [10].
83     //]
84 }
85 
custom4()86 void custom4() {
87     //[custom4
88     /*`
89         Our example now becomes
90     */
91     std::vector<int> vec;
92     any<has_push_back<_self, int>, _self&> c(vec);
93     c.push_back(10);
94     /*`
95         which is what we want.
96     */
97     //]
98 }
99 
100 //[custom
101 //` (For the source of the examples in this section see
102 //` [@boost:/libs/type_erasure/example/custom.cpp custom.cpp])
103 //` [custom1]
104 //` [custom2]
105 //` [custom3]
106 //` [custom4]
107 //]
108