![]() |
Home | Libraries | People | FAQ | More |
(For the source of the examples in this section see basic.cpp)
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.
Now, this example doesn't do very much. x
is approximately equivalent to a 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
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(push_back) 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.
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.
Member functions can be const.
BOOST_TYPE_ERASURE_MEMBER(empty) bool is_empty(any<has_empty<bool() const>, const _self&> x) { return x.empty(); }
For free functions, we can use the macro BOOST_TYPE_ERASURE_FREE.
BOOST_TYPE_ERASURE_FREE(getline) 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); }