| 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>(arg&: 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(push_back) |
| 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(a: i); |
| 82 | } |
| 83 | |
| 84 | /*` |
| 85 | We use the macro __BOOST_TYPE_ERASURE_MEMBER |
| 86 | to define a concept called `has_push_back`. |
| 87 | When we use `has_push_back`, we have to |
| 88 | tell it the signature of the function, `void(int)`. |
| 89 | This means that the type we store in the any |
| 90 | has to have a member that looks like: |
| 91 | |
| 92 | `` |
| 93 | void push_back(int); |
| 94 | `` |
| 95 | |
| 96 | Thus, we could call `append_many` with `std::vector<int>`, |
| 97 | `std::list<int>`, or `std::vector<long>` (because `int` is |
| 98 | convertible to `long`), but not `std::list<std::string>` |
| 99 | or `std::set<int>`. |
| 100 | |
| 101 | Also, note that `append_many` has to operate directly |
| 102 | on its argument. It cannot make a copy. To handle this |
| 103 | we use `_self&` as the second argument of __any. `_self` |
| 104 | is a __placeholder. By using `_self&`, we indicate that |
| 105 | the __any stores a reference to an external object instead of |
| 106 | allocating its own object. |
| 107 | */ |
| 108 | |
| 109 | /*` |
| 110 | Member functions can be const. |
| 111 | */ |
| 112 | BOOST_TYPE_ERASURE_MEMBER(empty) |
| 113 | bool is_empty(any<has_empty<bool() const>, const _self&> x) { |
| 114 | return x.empty(); |
| 115 | } |
| 116 | |
| 117 | /*` |
| 118 | For free functions, we can use the macro __BOOST_TYPE_ERASURE_FREE. |
| 119 | */ |
| 120 | |
| 121 | BOOST_TYPE_ERASURE_FREE(getline) |
| 122 | std::vector<std::string> read_lines(any<has_getline<bool(_self&, std::string&)>, _self&> stream) |
| 123 | { |
| 124 | std::vector<std::string> result; |
| 125 | std::string tmp; |
| 126 | while(getline(t: stream, t&: tmp)) |
| 127 | result.push_back(x: tmp); |
| 128 | return result; |
| 129 | } |
| 130 | |
| 131 | /*` |
| 132 | The use of `has_getline` is very similar to `has_push_back` above. |
| 133 | The difference is that the placeholder `_self` is passed in |
| 134 | the function signature instead of as a separate argument. |
| 135 | |
| 136 | The __placeholder doesn't have to be the first argument. |
| 137 | We could just as easily make it the second argument. |
| 138 | */ |
| 139 | |
| 140 | |
| 141 | void read_line(any<has_getline<bool(std::istream&, _self&)>, _self&> str) |
| 142 | { |
| 143 | getline(t&: std::cin, t: str); |
| 144 | } |
| 145 | |
| 146 | //] |
| 147 | |
| 148 | //[basic |
| 149 | //` (For the source of the examples in this section see |
| 150 | //` [@boost:/libs/type_erasure/example/basic.cpp basic.cpp]) |
| 151 | //` [basic1] |
| 152 | //` [basic2] |
| 153 | //` [basic3] |
| 154 | //] |
| 155 | |