| Home | Libraries | People | FAQ | More

## Basic Usage

(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((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);
    }