Boost logo

Boost :

Subject: Re: [boost] Any interest in dynamic dispatching mechanism from " interface" to template functions ?
From: Raffi Enficiaud (raffi.enficiaud_at_[hidden])
Date: 2010-07-01 18:48:45


Larry Evans <cppljevans <at> suddenlink.net> writes:

> The test driver code:
>
> http://preview.tinyurl.com/2a9dlun
>
> tests something similar; however, it doesn't use fusion::vector
> to store the argument references. Instead it uses:
>
> template<typename... ArgTypes>
> struct void_ptr_array
> {
> void* my_ptrs[sizeof...(ArgTypes>;
> ...
> };
>
> The void* are cast to whatever the ArgTypes indicate
> the actual variables types happen to be.

Ok, I think I got the idea. In the current implementation,
I wanted the types qualified and avoiding "void*". So I
can also perform compile-time checks on the consistency
of the convertors available.

> However,
> I'm not sure that's completely portable. OTOH,
> one advantage, at least I think, is that the abstract
> args and their corresponding concrete values can be
> stored (or at least pointers to them) in the same
> memory locations by just changing the ArgTypes... .

If possible, reference to initial objects are stored.
If not, a holder creates an appropriate temporary type
during the call. This temporary is then reconverted to
the interface type at the end of the call, if the
interface type is a non-const ref, or the convertor
tells that the matching needs a back-conversion.
So similar types (trivial conversion) for instance will
not be copied or dereferenced at all. Same for the
conversion from a base class to a daughter class.

> FWIW, I did try using a fusion container; however,
> I was using one container for the abstract args,
> and another for the concrete args, and pop_front'ing
> from the abstract arg container while push_backing
> to the concrete arg container, which I thought was
> a bit of a waste.

In fact, there is a bit of indirection in my
implementation.
The fusion container I use stores the interface
parameters. The other container is an mpl sequence
since there is no value associated to it before
the call to the function.
 
In fact, I create a fusion sequence of
"convertor_wrapper", each having an implicit
conversion to the template argument type and a
special destructor. The implicit conversion calls
the underlying convertor. These conversions are made
if and only if all the convertor_wrapper in the
chain of conversion are able to return a value
corresponding to the template argument, otherwise
no conversion is performed.
I use for that "fusion::invoke", with the sequence
of convertor_wrappers.
I think this is quite ok for the portability, since
it only involves the implicit cast operators of each
convertor_wrapper (I tested it on MSVC 2008Expr,
GCC 4.01 & GCC 4.4.1).

>
> Anyway, the dispatching code in reify_apply.hpp:
>
> http://preview.tinyurl.com/2ah2kpx
>
> can be used for either a variant type structure
> (like that in:
>
> variadic_templates/boost/composite_storage/pack/container_one_of_maybe.hpp
> )
> by using reifier_switch.hpp,
>
> or one with virtual functions to do the dispatching, like
> in the visitor pattern, as done with reifier_visitor.hpp.

I will have a look at this code soon !

>
> The test driver uses either one based on the value of the
> REIFIER_VISITOR macro.
>
> It differs from the apply_visitor in that it can be used
> for any number of arguments, since sizeof...(ArgTypes)
> can be any number.
>
> What maybe different from your method, I think, is suggested
> by:
>
> > The dispatch_object tests for the convertibility of each instance ui
> > of the arguments Ui of the interface function, with the corresponding
> > argument Ti
> > of the template function.
>
> I think that job is done by the:
>
> apply_ftor_check_args
>
> in apply_unpack.hpp.

Almost, but not exactly. For instance line 83 of
apply_unpack.hpp:

typename function_types::
can_be_called<Functor(Args const&...)>::type
is_ftor_args_callable;

The fact is that the Functor itself is not always
directly callable with the Args, and there is two
sequences of Args that should be considered: the one
for the interface and the other for the arguments of
the template function. So the
level of indirection induced by the convertors
mentioned earlier should be considered.
For instance a base class pointer to a derived class
reference (again... :) ). All these logics are
embedded in the convertors, defined for each
pair of types (interface, concrete), which make it
very easy to extend to new types.

> I think mabye what you mean by:
>
> > It also includes a "back conversion" for Ui's that are non-const
> > reference or pointers.
>
> is done by the:
>
> arg_type*ap=static_cast<arg_type*>(vp);
> return *ap;
>
> in void_ptr_array::project in replace_source_with_target_ptr.hpp.
>
> -regards,
> Larry
>
So here again, I think there is a need for an indirection
level. The conversion is not always static (std::map& to
variant& for instance). But maybe I missed some point ?

Thanks for your feedback !

Regards,
Raffi


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk