| // Boost.TypeErasure library |
| // |
| // Copyright 2011 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/member.hpp> |
| #include <boost/type_erasure/free.hpp> |
| #include <boost/mpl/vector.hpp> |
| #include <iostream> |
| #include <vector> |
| |
| namespace mpl = boost::mpl; |
| using namespace boost::type_erasure; |
| |
| void basic1() { |
| //[basic1 |
| /*` |
| The main class in the library is __any. An __any can |
| store objects that meet whatever requirements we specify. |
| These requirements are passed to __any as an MPL sequence. |
| |
| [note The MPL sequence combines multiple concepts. |
| In the rare case when we only want a single concept, it doesn't |
| need to be wrapped in an MPL sequence.] |
| */ |
| any<mpl::vector<copy_constructible<>, typeid_<>, relaxed> > x(10); |
| int i = any_cast<int>(x); // i == 10 |
| /*` |
| __copy_constructible is a builtin concept that allows us to |
| copy and destroy the object. __typeid_ provides run-time |
| type information so that we can use __any_cast. __relaxed |
| enables various useful defaults. Without __relaxed, |
| __any supports /exactly/ what you specify and nothing else. |
| In particular, it allows default construction and assignment of __any. |
| */ |
| //] |
| } |
| |
| void basic2() { |
| //[basic2 |
| /*` |
| Now, this example doesn't do very much. `x` is approximately |
| equivalent to a [@boost:/libs/any/index.html boost::any]. |
| We can make it more interesting by adding some operators, |
| such as `operator++` and `operator<<`. |
| */ |
| any< |
| mpl::vector< |
| copy_constructible<>, |
| typeid_<>, |
| incrementable<>, |
| ostreamable<> |
| > |
| > x(10); |
| ++x; |
| std::cout << x << std::endl; // prints 11 |
| //] |
| } |
| |
| //[basic3 |
| /*` |
| The library provides concepts for most C++ operators, but this |
| obviously won't cover all use cases; we often need to |
| define our own requirements. Let's take the `push_back` |
| member, defined by several STL containers. |
| */ |
| |
| BOOST_TYPE_ERASURE_MEMBER((has_push_back), push_back, 1) |
| |
| void append_many(any<has_push_back<void(int)>, _self&> container) { |
| for(int i = 0; i < 10; ++i) |
| container.push_back(i); |
| } |
| |
| /*` |
| We use the macro __BOOST_TYPE_ERASURE_MEMBER |
| to define a concept called `has_push_back`. |
| The second parameter is the name of the member |
| function and the last macro parameter indicates |
| the number of arguments which is `1` since `push_back` |
| is unary. When we use `has_push_back`, we have to |
| tell it the signature of the function, `void(int)`. |
| This means that the type we store in the any |
| has to have a member that looks like: |
| |
| `` |
| void push_back(int); |
| `` |
| |
| Thus, we could call `append_many` with `std::vector<int>`, |
| `std::list<int>`, or `std::vector<long>` (because `int` is |
| convertible to `long`), but not `std::list<std::string>` |
| or `std::set<int>`. |
| |
| Also, note that `append_many` has to operate directly |
| on its argument. It cannot make a copy. To handle this |
| we use `_self&` as the second argument of __any. `_self` |
| is a __placeholder. By using `_self&`, we indicate that |
| the __any stores a reference to an external object instead of |
| allocating its own object. |
| */ |
| |
| /*` |
| There's actually another __placeholder here. The second |
| parameter of `has_push_back` defaults to `_self`. If |
| we wanted to define a const member function, we would |
| have to change it to `const _self`, as shown below. |
| */ |
| BOOST_TYPE_ERASURE_MEMBER((has_empty), empty, 0) |
| bool is_empty(any<has_empty<bool(), const _self>, const _self&> x) { |
| return x.empty(); |
| } |
| |
| /*` |
| For free functions, we can use the macro __BOOST_TYPE_ERASURE_FREE. |
| */ |
| |
| BOOST_TYPE_ERASURE_FREE((has_getline), getline, 2) |
| std::vector<std::string> read_lines(any<has_getline<bool(_self&, std::string&)>, _self&> stream) |
| { |
| std::vector<std::string> result; |
| std::string tmp; |
| while(getline(stream, tmp)) |
| result.push_back(tmp); |
| return result; |
| } |
| |
| /*` |
| The use of `has_getline` is very similar to `has_push_back` above. |
| The difference is that the placeholder `_self` is passed in |
| the function signature instead of as a separate argument. |
| |
| The __placeholder doesn't have to be the first argument. |
| We could just as easily make it the second argument. |
| */ |
| |
| |
| void read_line(any<has_getline<bool(std::istream&, _self&)>, _self&> str) |
| { |
| getline(std::cin, str); |
| } |
| |
| //] |
| |
| //[basic |
| //` (For the source of the examples in this section see |
| //` [@boost:/libs/type_erasure/example/basic.cpp basic.cpp]) |
| //` [basic1] |
| //` [basic2] |
| //` [basic3] |
| //] |