Boost logo

Boost :

From: Tom Bachmann (e_mc_h2_at_[hidden])
Date: 2007-03-17 11:21:49


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I hope it is not considered bad style to propose new functionality in
the very first message. I have been using boost for more than a year and
I have found it incredibly helpful, and now I'm considering to "give
back something". I have to admit, however, that I have experianced boost
purely from a user perspective.

[Please note that all code examples are more or less pseudo code, solely
meant to illustrate my points.]

The first thing I'd like to propose is a wrapper around std::type_info.
I think it is well known (e.g. alexandrescu calls it TypeInfo), so I
wonder if it's just my stupidity not to find it, although there's
already something in boost. If not, here's the idea:
Sometimes (e.g. when implementing multidispatching), you want to take
std::type_info as key in a std::map. However, std::type_info does not
implement op<, therefor this is not directly possible.
std::type_info::before, on the other hand, does implement ordering.
The (one?) basic solution is to use a wrapper around std::type_info that
handles the subtleties, it'd look somewhat like:

struct type_wrapper
{
  const std::type_info& t;

  type_wrapper (const std::type_info& t_)
    : t (t_)
  {
  }

  bool operator< (const type_wrapper& o) const
  {
    return t.before (o.t);
  }

  // ...
}

This is a very small and (I think) straightforward construct and should
be absolutely portable. It's scope of use might be somewhat limited,
because the rtti is usually tried to be avoided, but despite that, I
think, type_wrapper would fit pretty nicely into the rest of boost.

My other proposal is a bit larger: I wonder if a generic
multidispatching infrastructure would be wanted. Due to alexandrescu's
book multidispatching was one of the first advanced topics I worked
with. Two years ago or so I wrote a static multidispatcher (that is,
multidispatching using template-generated if-else chains that use
dynamic_cast). Currently I came across the need for multidispatching
again, and I wrote a simple dynamic dispatcher. The infrastructure has
greatly improved since I wrote the static multidispatcher (or I was not
aware of it when I wrote the static one), I think a fairly general
dispatching infrastructure can be implemented now.

Now to get a bit more specific:
The building block of the infrastructure I'm thinking of is a dynamic
general dispatcher. That is, a function object that calls other function
objects depending on certain properties of it's arguments, e.g. like this:

... dispatcher;
dispatcher.add (1, foo);
dispatcher.add (3, bar);
dispatcher (1, "hello", 3); // foo (1, "hello", 3)
dispatcher (2, "hello", 3); // exception

Internally, the dispatcher manages a std::map to find the right function
object to call. It has to be paremeterized to extract the properties
that determine the function object to call:

template
  <
    ...
    class Accessor,
    ...
>
class dispatcher
{
private:
  typedef ... fn_t;
  typedef typename Accessor::key_t key_t;
  typedef std::map<key_t, fn_t> map_t;

  map_t m;

public:
  ... run (<arguments>)
  {
    map_t::iterator it = m.find (Accessor::extract_key (<arguments>));
    if (it == m.end ())
      ...
    return it -> second (<arguments>);
  }
};

For the example above, Accessor could look like this:

struct example_accessor
{
  typedef int key_t;
  static int extract_key (int k, const std::string&, int)
  {
    return k;
  }
};

One problem is passing parameters to dispatcher::run. I think the most
sensible way is to make run take a single tuple as argument, and to
generate wrappers around it using Boost.Preprocessor.

Typical multidispatching (based on argument types) can now be
implemented easily, using an accessor like this:

struct type_accessor
{
  typedef boost::tuple<type_wrapper, type_wrapper, type_wrapper> key_t;

  template<class T1, class T2, class T3>
  static key_t extract_key (const T1& t1, const T2& t2, const T3& t3,
                            int, bool, std::string, ...)
  {
    return key_t (typeid (t1), typeid (t2), typeid (t3));
  }
};

Also, one could imagine some convenience wrappers for typical
multidispatching, looking e.g. like:

make (spec, obj1, obj2, obj3, obj4).run (a, b, c);

// multi_obj is a class generated by the user with
// some sort of assistance from the library
multi_obj m (obj1, obj2);
m.foo (3, a);
m.bar ('a', 0, 3);

Such a construction would be portable and reusable, and quite useful
under some circumstances. I'm not sure if it's in the scope of boost,
though.
- --
- -ness-
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFF/AeNvD/ijq9JWhsRAuf0AJ97rcMUvHFL7+6qmhVUfy5R39KxNgCbBBIK
ls7cmxTXgulXmzccS60eY8g=
=Y+CH
-----END PGP SIGNATURE-----


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