|
Boost : |
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2007-09-08 14:02:18
AMDG
"Marco Costalba" <mcostalba_at_[hidden]> wrote:
> Sorry, but I don't understand, could you please post an example of how
> to use the dispatcher so to see 'struct implicit_conversion' at work ?
>
> Thanks
> Marco
>
The code I posted was not well thought out. The set of implicit conversions
should probably be global. I would want to write
make_implicit_conversion<double, int>();
make_implicit_conversion<int, double>();
Somewhere during initialization to say that int is convertible
to double and double to int.
Here's a more complete implementation (warning untested)
I'm not showing how to register functions. That would involve
creating a function object that casts from void* to the actual type.
A real implementation would probably also use Boost.Function
instead of function pointers.
struct wrap_typeinfo {
friend bool operator<(const wrap_typeinfo& lhs, const wrap_typeinfo&
rhs) {
return(lhs.key.before(rhs.key));
}
const std::type_info* impl;
};
struct implicit_conversion {
friend bool operator<(const implicit_conversion& lhs, const
implicit_conversion& rhs) {
return(lhs.from.before(rhs.from));
}
const std::type_info* to;
void* (*convert)(void*);
void (*destroy)(void*);
};
static std::multi_map<wrap_typeinfo, implicit_conversion> all_conversions;
void* ignore_convert(void* x) {
return(x);
}
void ignore_destroy(void*) {}
static implicit_conversion no_conversion = {
0,
0,
&ignore_convert
&ignore_destroy
};
template<class To>
void destroy(void* victim) {
delete static_cast<To*>(victim);
}
template<class From, class To>
void* convert(void* from) {
return new To(*static_cast<From*>(from));
}
template<class From, class To>
void make_implicit_conversion() {
wrap_typeinfo from = { &typeid(From) };
implicit_conversion result = {
&typeid(To),
&convert<From, To>,
&destroy<From, To>
};
all_conversions.insert(std::make_pair(from, result));
}
template<class R>
struct dispatcher0 {
public:
R operator()() const {
return(f0());
}
private:
R (*f0)();
};
template<class F>
F get_function(F f, const std::type_info**, const implicit_conversion**) {
return(f);
}
template<class F, class T>
F get_function(const std::map<wrap_typeinfo, T>& m, wrap_typeinfo*
types, const implicit_conversion** out) {
std::map<wrap_typeinfo, T>::iterator iter = m.find(*types);
if(iter != m.end()) {
++types;
*out++ = &no_conversion;
return(get_function<F>(t.value, types, out));
} else {
BOOST_FOR_EACH(const implicit_conversion& conversion,
all_conversions.equal_range(*types)) {
std::map<wrap_typeinfo, T>::iterator iter =
m.find(*conversion.from);
if(iter != m.end()) {
++types;
*out++ = &conversion;
return(get_function<F>(iter->second, types, out));
}
}
}
return(0);
}
template<int N>
struct cleanup_array : cleanup_array<N - 1> {
cleanup_array(implicit_conversion* c, void** data) : cleanup_array<N
- 1>(c) {
x = c[N - 1].convert(data[N-1]);
}
~cleanup_array() {
cleanup_array<N - 1>::conversions[N-1].destroy(x);
}
void* x;
};
template<>
struct cleanup_array<0> {
implicit_conversion* conversions;
cleanup_array(implicit_conversion* c, void**) : conversions(c) {}
};
template<int N, int N2>
void* get(cleanup_array<N2>& from) {
return(static_cast<cleanup_array<N+1>&>(from).x);
}
template<class R>
struct dispatcher1 {
public:
template<class T0>
R operator()(T0 t0) const {
wrap_typeinfo types[1] = { &typeid(T0) };
implicit_conversion* conversions[1];
R (*f)(void*) = get_function<R(*)(void*)>(f1, types, conversions);
void* elements[1] = { &t0 };
cleanup_array<1> data(conversions, elements);
return(f(get<0>(data)));
}
private:
std::map<wrap_typeinfo, R(*)(void*)> f1;
};
template<class R>
struct dispatcher2 {
public:
template<class T0, class T1>
R operator()(T0 t0, T1 t1) const {
wrap_typeinfo types[2] = { &typeid(T0), &typeid(T2) };
implicit_conversion* conversions[2];
R (*f)(void*) = get_function<R(*)(void*, void*)>(f2, types,
conversions);
void* elements[2] = { &t0, &t1 };
cleanup_array<2> data(conversions, elements);
return(f(get<0>(data), get<1>(data)));
}
private:
std::map<wrap_typeinfo, std::map<wrap_typeinfo, R(*)(void*, void*)>
> f2;
};
In Christ,
Steven Watanabe
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk