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