Boost logo

Boost :

From: Dean Michael Berris (mikhailberis_at_[hidden])
Date: 2007-09-30 09:58:42


Hi Marco!

On 9/30/07, Marco Costalba <mcostalba_at_[hidden]> wrote:
> On 9/30/07, Dean Michael Berris <mikhailberis_at_[hidden]> wrote:
> >
> > Comments and suggestions would be most appreciated.
> >
>
> Very nice work. I have found a lot of things are very similar to my
> simple_factory, especially now that has been ported to boost::fusion.
>

Thank you very much. I do my best. :)

> But your code is more well organized, although I find it a little bit
> difficult for me, as example is not clear to me the whole part
> regarding the invokers, indeed from your example code
>
> void function(int argument) {
> // do something;
> };
>
> //...
> dispatch::dispatcher<void (int), int> d;
> d[0] = function;
>
> //...
> int input;
> std::cin >> input;
> d[0](input);
>
> is not clear to me when and where this invokers are called given that
> dispatcher::operator[] returns a function object reference. Or perhaps
> I misread.
>

Can you refer to which page in the documentation you see that?

The invoker is intended to be used this way:

(Refers to documentation page on Invoker in the Library Design section)
boost::dispatch::dispatcher<void ()> void_dispatcher;
boost::dispatch::invoke_(void_dispatcher)() << 0 << 1 << 2;

The inoke_(void_dispatcher)() returns a callable object, which
encapsulates a reference to the dispatcher instance. The operator<<'s
allow you to pass indexes to this callable invoker object, which are
used in indexing the dispatcher using the operator[] definition for
the particular dispatcher.

Invokers are useful if you want to write functions which take in a
reference to an existing dispatcher, and then specify some sort of
invocation sequence with an easier interface. Example would be:

template <class DispatcherType, class InputType>
void setup_sequence(DispatcherType & dispatcher, InputType const & input) {
  try {
    enum { INIT, CONNECT, REQUEST, DISCONNECT, PROCESS };
    boost::dispatch::invoke_(dispatcher)(input) << INIT
        << CONNECT << REQUEST << DISCONNECT << PROCESS;
  } catch (boost::dispatch::unregistered_handler & e) {
    // fail gracefully?
  };
};

> One very little point is why you use default template parameters here;
>
> template <typename Signature,
> typename IndexType = int,
> typename DecisionStrategy = boost::dispatch::detail::always_true<IndexType>,
> typename RoutingStrategy =
> boost::dispatch::detail::default_routing<IndexType>
> >
> struct registry_impl
>
>
>
> If it is instantiated only from here:
>
>
> template <typename Signature,
> typename IndexType = int,
> typename DecisionStrategy = boost::dispatch::detail::always_true<IndexType>,
> typename RoutingStrategy =
> boost::dispatch::detail::default_routing<IndexType>
> >
> struct dispatcher : public boost::dispatch::detail::registry_impl <Signature,
> IndexType,
> DecisionStrategy,
> RoutingStrategy
> >
>
> where default parameters are already set.
>

Yes, good observation. Actually this is a remnant of a refactoring I
performed a couple of releases back. This also allows anyone
(currently, just me) to extend the dispatcher concept to use a
different back-end implementation with minimal disruption.

But generally, the template defaults are just there -- they don't hurt
anyone really. ;-)

> >
> > This still does not implement the multiple-signature feature which I'm
> > still contemplating on putting in, but this is already useful by
> > itself.
> >
>
> Once I have grasped more with your code would be nice to add this
> part, or possibly to share your opinion on how to do it. As example
> simple_factory uses a multimap to achieve this.
>
> But the most difficult part is to allow "relaxed" type checking on
> function arguments. As example
>
> void function(int& counter) {
> counter++;
> };
>
> //...
> dispatch::dispatcher<void (int&), int> d;
> d[0] = function;
>
> //...
> int input = 6;
> d[0](input);
>
> std::cout << input << "\n"; // should be 7 now.
>
> This is difficult with multiple-signature feature. I have implemented
> this in simple_factory, but was not straightforward and I doubts my
> approach is the best possible one, so I would really like to share
> your implemantation ideas on this.
>

The immediate "top of my head" implementation would be to do a linear
inheritance of the different Functor objects that support different
signatures to represent a multi-signature Functor wrappers. If you
will endulge, the concept is pretty simple (though not really straight
forward to implement without using help from Boost.Fusion/Boost.MPL):

typedef dispatcher< signatures<void(int), void(double), void(string)>
> multi_index_dispatcher;

multi_index_dispatcher will then contain Functor objects of the form:

struct Functor<void(double)> : Functor<void(string)> { };
struct Functor<void(int)> : Functor<void(double)> { };

and the result will be a Functor<void(int)> that inherits from
Functor<void(double)> that inherits from Functor<void(string)> -- I
believe this can be implemented with Boost.Fusion/MPL `fold`, how I'm
not entirely sure yet. But the resulting type will have operator()
overloads of different signatures -- which signature is chosen is
determined at compile time. So given the above and then the following:

void foo(double d) ;
void bar(string s) ;
void fizz(int i) ;

multi_index_dispatcher d;
d[0] = foo; // valid, will register the void(double)
d[0] = bar; // valid, will register the void(string)
d[0] = fizz; // valid, will register the void(int)
d[0](1.0); // valid, will call the void(double)
d[0](1); // valid, will call the void(int)
d[0]("1"); // valid, will call the void(string)

This might also be achievable with an encapsulated Fusion map instead
of linear inheritance, but I'm not entirely sure about being able to
generate the appropriate type-safe operator() overloads in that
manner.

> Thanks
> Marco

Thank you for the interest, and I definitely hope the above
explanation helps. :)

-- 
Dean Michael C. Berris
Software Engineer, Friendster, Inc.
[http://cplusplus-soup.blogspot.com/]
[mikhailberis_at_[hidden]]
[+63 928 7291459]
[+1 408 4049523]

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