|
Boost : |
From: Corwin Joy (cjoy_at_[hidden])
Date: 2001-07-20 17:13:40
So, one of the things I uploaded to boost recently was a class for
'registering' and performing casts on an 'any' variable. The idea
(partially suggested by Peter Dimov) is to do a lookup in a type table to
get a registered cast function for the conversion and then pull this
function out to do the operation. One idea that has facinated me for a
while is the concept of an 'any' object. The idea is to hold an object of a
polymorphic type, register available methods, and then work with it
polymorphically as a proper object. Mike Gradman and I have a brief paper
on how to do this with callback methods that leads to quite an interesting
object structure where the methods & heirarchy can be configured at runtime
etc. (See http://www.geocities.com/corwinjoy/vo/VariantObject.htm for
details and source code).
One thing that occurs to me, however is that you could actually push the
conversion library listed above even further to obtain a nifty runtime
registration of operations versus any objects without even requiring any
custom classes. Suppose, for example that I wanted to write a header which
I will call 'any_operators.hpp'. The idea is loosely similar to boost
operators.hpp in that what I want to do is register that a particular type
of class supports addition operations from within any:
any_addable<T> {
// constructor 'registers' add operations as available for this class to
the global 'any' method registry
}
etc.
so that, say, any_operators<T>() would go ahead and register that arithmetic
operators were available for the type T.
Then what we do is define a helper class, say any_invoke that can construct
from an 'any' class and provides translation for the operators '+', '-', '*'
etc.
So, e.g
any_operators<double>(); // register that arithmetic operators are
available for type double
double d1(.5), d2(2.5);
any a1(d1), a2(d2);
any b = a1 + a2; // what happens here!
on this last line the compiler would recognize that it can construct an
any_invoke class from any and iterpret this as:
any b = any_invoke(a1) + any_invoke(a2);
so, essentially, we could declare an any_invoke class as:
class any_invoke {
private:
any &a_;
public:
any_invoke(any & a) : a_(a) {};
any_invoke& operator +=(const any_invoke &rhs) {
// call registered + operator on a_ in function registry
return *this;
}
operator any() const {return a_;}
};
any_invoke operator +(const any_invoke &lhs, const any_invoke &rhs) {
any_invoke tmp(lhs);
tmp += rhs;
return tmp;
}
The point of this is that, without losing generality of the existing any
class, we can register methods to invoke class operations on polymorphic
data types. So now we could have a vector of 'any' and operations like
transform(any_vector.begin(), any_vector.end(), some_function) will be
allowed provided that all classes in the vector have registered support for
the given function. Anyway, if you combine this with a callback library you
can extend this idea to any kind of function/method invoke on an 'any' data
object. Even cooler, the registration isn't such a bear since you can
create classes to do it automatically, e.g.
class any_addable : public any {
public:
template<typename T> any_addable(const T &t) : any(T){
// class must be able to register addition operators to
// compile / be considered addable
any_addable_operators<T>();
}
}
So now you can have functions to take variant objects with methods like we
do in DTL but register the methods a bit more cleanly.
sort(vector<any> v());
(This can sort an any vector succesfully as long as all classes held by the
vector have been previously registered elsewhere).
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk