Boost logo

Boost :

From: Alexander Nasonov (alnsn_at_[hidden])
Date: 2002-11-11 08:32:32


I'm trying to redesign functions for dynamic_any. Currenly, I have this:

  struct less : function_vv<bool>
  {
    template<typename T>
    bool operator()(const T & a, const T & b) const
    {
      return a < b;
    }
  };

Two trailing 'v' in function_vv are indicators that less accepts two
arguments by value or const reference. First change I'm going to make is to
remove these trailing letters and to introduce more natural syntax (idea is
taken from Boost.Function):

  struct less : function<bool (const arg &, const arg &)>
  {
    template<typename Arg>
    bool operator()(const Arg & a, const Arg & b) const
    {
      return a < b;
    }
  };

The 'arg' is a placeholder for pseudo-template parameter. Compare it with
Arg defined in less::operator() and with less::operator() signature.

This change doesn't solve other problem: using of a 'call' function:

  using namespace boost;
  using namespace boost::dynamic_any;

  any<mpl::list<less> > a, b;
  bool result = call(less(), a, b); // here is a problem

I would like it to be:

  any<mpl::list<less> > a, b;
  bool result = less()(a, b); // much better

Curiously recurring pattern suits fine here. Let the class template
'function' to accept end function (less in our case). Call operator that
takes two 'any' values can be implemented inside the 'function' (constness
of arguments leaved apart for simplicity):

  template<class EndFunction, typename Signarure>
  struct function
  {
    template<class OperationLlist>
    typename function_result<OperationList, EndFunction>::type
    operator()(any<OperationList> & a, any<OperationList> & b)
    {
      // implementation
    }

    // implementation
  };

But it will be hidden by the call operator defined in EndFunction.
EndFunction::operator() should be renamed:

  struct less : function<less, bool (const arg &, const arg &)>
  {
    // note the name
    template<typename Arg>
    bool call(const Arg & a, const Arg & b) const
    {
      return a < b;
    }
  };

Additionally, two types of control are desired:
1) Control over real types of arguments. It is a limitation of dynamic_any
library that arguments must be converted to _one_ type before a call. But
they can be of different types. Problem can be easily solved by adding
additional arguments to the 'call' member-function:

  template<typename Arg>
  bool less::call(const Arg & a, const std::type_info & ta,
                  const Arg & b, const std::type_info & tb) const
  {
    return a < b;
  }

2) Controlled behavior when the call cannot be made. I propose to make it
over 'nocall' member-function. Default handler can be implemented inside
the 'function' as a single throw statement. Those users who wish other
behavior can override 'nocall'.

As a summary I can demonstrate less function that compares first by type and
then by value:

  struct less : function<less, bool (const arg &, const arg &)>
  {
    template<typename Arg>
    bool call(const Arg & a, const std::type_info & ta,
              const Arg & b, const std::type_info & tb) const
    {
      return (ta == tb) ? (a < b) : ta.before(tb);
    }

    template<typename OperationList>
    bool nocall(const any<OperationList> & ta,
                const any<OperationList> & tb) const
    {
      return a.type().before(b.type());
    }
  };

  // Example:
  typedef any<mpl::list<less> > any_less;
  std::vector<any_less> v = get_it();
  std::sort(v.begin(), v.end(), less());

How do you like it?

Best regards,
Alexander Nasonov
mailbox: alnsn
server: mail.ru


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