]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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/any_cast.hpp> | |
13 | #include <boost/type_erasure/builtin.hpp> | |
14 | #include <boost/type_erasure/operators.hpp> | |
15 | #include <boost/type_erasure/member.hpp> | |
16 | #include <boost/type_erasure/free.hpp> | |
17 | #include <boost/mpl/vector.hpp> | |
18 | #include <iostream> | |
19 | #include <vector> | |
20 | ||
21 | namespace mpl = boost::mpl; | |
22 | using namespace boost::type_erasure; | |
23 | ||
24 | void basic1() { | |
25 | //[basic1 | |
26 | /*` | |
27 | The main class in the library is __any. An __any can | |
28 | store objects that meet whatever requirements we specify. | |
29 | These requirements are passed to __any as an MPL sequence. | |
30 | ||
31 | [note The MPL sequence combines multiple concepts. | |
32 | In the rare case when we only want a single concept, it doesn't | |
33 | need to be wrapped in an MPL sequence.] | |
34 | */ | |
35 | any<mpl::vector<copy_constructible<>, typeid_<>, relaxed> > x(10); | |
36 | int i = any_cast<int>(x); // i == 10 | |
37 | /*` | |
38 | __copy_constructible is a builtin concept that allows us to | |
39 | copy and destroy the object. __typeid_ provides run-time | |
40 | type information so that we can use __any_cast. __relaxed | |
41 | enables various useful defaults. Without __relaxed, | |
42 | __any supports /exactly/ what you specify and nothing else. | |
43 | In particular, it allows default construction and assignment of __any. | |
44 | */ | |
45 | //] | |
46 | } | |
47 | ||
48 | void basic2() { | |
49 | //[basic2 | |
50 | /*` | |
51 | Now, this example doesn't do very much. `x` is approximately | |
52 | equivalent to a [@boost:/libs/any/index.html boost::any]. | |
53 | We can make it more interesting by adding some operators, | |
54 | such as `operator++` and `operator<<`. | |
55 | */ | |
56 | any< | |
57 | mpl::vector< | |
58 | copy_constructible<>, | |
59 | typeid_<>, | |
60 | incrementable<>, | |
61 | ostreamable<> | |
62 | > | |
63 | > x(10); | |
64 | ++x; | |
65 | std::cout << x << std::endl; // prints 11 | |
66 | //] | |
67 | } | |
68 | ||
69 | //[basic3 | |
70 | /*` | |
71 | The library provides concepts for most C++ operators, but this | |
72 | obviously won't cover all use cases; we often need to | |
73 | define our own requirements. Let's take the `push_back` | |
74 | member, defined by several STL containers. | |
75 | */ | |
76 | ||
77 | BOOST_TYPE_ERASURE_MEMBER((has_push_back), push_back, 1) | |
78 | ||
79 | void append_many(any<has_push_back<void(int)>, _self&> container) { | |
80 | for(int i = 0; i < 10; ++i) | |
81 | container.push_back(i); | |
82 | } | |
83 | ||
84 | /*` | |
85 | We use the macro __BOOST_TYPE_ERASURE_MEMBER | |
86 | to define a concept called `has_push_back`. | |
87 | The second parameter is the name of the member | |
88 | function and the last macro parameter indicates | |
89 | the number of arguments which is `1` since `push_back` | |
90 | is unary. When we use `has_push_back`, we have to | |
91 | tell it the signature of the function, `void(int)`. | |
92 | This means that the type we store in the any | |
93 | has to have a member that looks like: | |
94 | ||
95 | `` | |
96 | void push_back(int); | |
97 | `` | |
98 | ||
99 | Thus, we could call `append_many` with `std::vector<int>`, | |
100 | `std::list<int>`, or `std::vector<long>` (because `int` is | |
101 | convertible to `long`), but not `std::list<std::string>` | |
102 | or `std::set<int>`. | |
103 | ||
104 | Also, note that `append_many` has to operate directly | |
105 | on its argument. It cannot make a copy. To handle this | |
106 | we use `_self&` as the second argument of __any. `_self` | |
107 | is a __placeholder. By using `_self&`, we indicate that | |
108 | the __any stores a reference to an external object instead of | |
109 | allocating its own object. | |
110 | */ | |
111 | ||
112 | /*` | |
113 | There's actually another __placeholder here. The second | |
114 | parameter of `has_push_back` defaults to `_self`. If | |
115 | we wanted to define a const member function, we would | |
116 | have to change it to `const _self`, as shown below. | |
117 | */ | |
118 | BOOST_TYPE_ERASURE_MEMBER((has_empty), empty, 0) | |
119 | bool is_empty(any<has_empty<bool(), const _self>, const _self&> x) { | |
120 | return x.empty(); | |
121 | } | |
122 | ||
123 | /*` | |
124 | For free functions, we can use the macro __BOOST_TYPE_ERASURE_FREE. | |
125 | */ | |
126 | ||
127 | BOOST_TYPE_ERASURE_FREE((has_getline), getline, 2) | |
128 | std::vector<std::string> read_lines(any<has_getline<bool(_self&, std::string&)>, _self&> stream) | |
129 | { | |
130 | std::vector<std::string> result; | |
131 | std::string tmp; | |
132 | while(getline(stream, tmp)) | |
133 | result.push_back(tmp); | |
134 | return result; | |
135 | } | |
136 | ||
137 | /*` | |
138 | The use of `has_getline` is very similar to `has_push_back` above. | |
139 | The difference is that the placeholder `_self` is passed in | |
140 | the function signature instead of as a separate argument. | |
141 | ||
142 | The __placeholder doesn't have to be the first argument. | |
143 | We could just as easily make it the second argument. | |
144 | */ | |
145 | ||
146 | ||
147 | void read_line(any<has_getline<bool(std::istream&, _self&)>, _self&> str) | |
148 | { | |
149 | getline(std::cin, str); | |
150 | } | |
151 | ||
152 | //] | |
153 | ||
154 | //[basic | |
155 | //` (For the source of the examples in this section see | |
156 | //` [@boost:/libs/type_erasure/example/basic.cpp basic.cpp]) | |
157 | //` [basic1] | |
158 | //` [basic2] | |
159 | //` [basic3] | |
160 | //] |