
AMDG 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) { ++t; } } any<increment> x(1); increment()(x); 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 operator+ 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 violating 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) { return(t[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 instead 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 increment 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