Boost logo

Boost :

From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2007-10-27 18:11:32


After 6+ months I've finally gotten back to this. I'd like to get
some feedback on my ideas before I continue. The current version is in
the vault.

The basic interface is derived from Alexander Nasonov's dynamic_any

struct increment : concept_<increment, void(_&)> {
    template<class T>
    static void execute(T& t) {

any<increment> x(1);
assert(type_erasure::any_cast<int>(x) == 1);

Note that unlike Boost.Function references will not work.
int i;
any<increment> x(boost::ref(i)); // NO!!

The reason is that if references were allowed it would be to easy to
kill yourself.
(I've been there. I allowed references at first and then implemented
in terms of operator+=. When the left argument is a reference this
means that
I made a shallow copy of the reference, called operator += on that, thus
the expectation that operator+ does not modify its arguments)

A function can also return another polymorphic object whose dynamic type
is different.

template<class R, class P2>
struct at : concept<at<R, P2>, R(const P2&, int)> {
    template<class T>
    static typename T::value_type execute(const T& t, int i) {

any<at<_1, _> > any_container(std::vector<int>(1, 2));
any<> value(at<_1, _>()(any_container, 0));
assert(type_erasure::any_cast<int>(value) == 2);

In this example _ is the placeholder that refers to the current object.
The placeholder _1 is used to refer to the return type of at.

Since there is a mechanism for handling multiple objects,
we can capture multiple objects simultaneously using a tuple:

template<class P1, class P2>
struct add : concept_<add<P1, P2>, P1(const P1&, const P2&)> {
    template<class T1, class T2>
    static T1 execute(const T1& t1, const T2& t2) {
        return(t1 + t2);

int array[] = {...};
type_erasure::tuple<_1, _2, where_<add<_1, _2> > > tuple(&array[0], 0);
any<> pointer_to_second_element(add<_1,
_2>()(type_erasure::get<0>(tuple), type_erasure::get<1>(tuple));
assert(type_erasure::any_cast<int*>(pointer_to_second_element) == array
+ 1);

The first two arguments to tuple<...> specify which placeholders
correspond to those
elements. The element 0 will be match _1 and element 1 will match _2.

Note that add is not a true multimethod. It's arguments must
ultimately come from the same place. i.e. you can apply it as many
times as you want since its return type is known to always be the
same as its first argument, but you cannot mix another type in e.g. long
of int.

Another thing to note is that it is always okay to discard functions.
In the
last example the result of calling add itself supports add since it is
the same type.
I don't care about that so I construct an any<> from it. I haven't
shown it here,
but any<...> takes up to 10 parameters or an MPL sequence. I can assign one
any<> to another which has an arbitrary subset of its functions. One
that has
both increment and decrement can be assigned to one that supports only
or to one that supports only decrement.

Future Work:

I intend to enable boost::ref iff there are no mutating operations for
the type.

There should be a class for references, so that you can throw away
some operations without making a copy.

I can implement multimethods if
    (a) The return type is fixed at compile time and
    (b) Every type specifies (through a traits template) a list of
possible overloads
         involving it.

Functions should be able to handle cases such as
template<class P1, class P2>
struct some_function : concept_<some_function<P1, P2>, void(const P1&,
const P2&)> {

any<some_function<_, std::string> > a1;
tuple<_1, _2, where_<some_function<_1, _2> > > t(a1, std::string("The
quick brown fox jumps over the lazy dog."));

where some of the arguments are any<>s and others are are of known type.

In Christ,
Steven Watanabe

Boost list run by bdawes at, gregod at, cpdaniel at, john at