Boost logo

Boost Users :

From: Chris Uzdavinis (cuzdav_at_[hidden])
Date: 2007-01-16 15:04:59


On 1/16/07, Peter Dimov <pdimov_at_[hidden]> wrote:
> Chris Uzdavinis wrote:
> > Can anyone tell me how to determine the arity of an arbitrary bind
> > object? I have a generic function that receives a bind object, but so
> > far I've been unable to detect at compile time how many arguments it
> > takes. Am I overlooking something obvious?
>
> No, there's no obvious way to determine the minimum arity of a bind object
> (its maximum arity is 9). What is the specific scenario? Does it have to be
> at compile time?

Hi, thanks for the feedback. I'll try to explain the situation
without going overboard.

I have several derived classes from an abstract base, each holding a
boost::function object with a slightly different signature, namely,
arity0 through arity N. When I instantiate one of these classes I
pass an object that matches its signature in arity.

To simplify creation of these objects, I have some overloaded
functions, make_func(), which take a function (or member function ptr
+ object address) and instantiate the correct derived class to wrap
it.

My goal is to make the generator functions work when given a boost
bind object. That is, I'd like to write a make_func() overload that
accepts a template type T, and when T is a bind object, it uses some
sort of MPL introspection to decide which derived class is required to
hold this bind object, instanties it, and returns the pointer, just
like all the other make_func generator functions do.

Here's some stripped down and simplified code. The very last function
is the one I don't know how to write. If only bind objects had a
"min_arity" member constant.... :)

class Function
{
public:
  typedef boost::shared_ptr<Function> Shptr;
  virtual ~Function() { }
  virtual std::string call() {error(0);}
  virtual std::string call(std::string const &) {error(1);}
  virtual int arity() const = 0;

private:
  void error(int num_args)
  {
    std::ostringstream msg;
    msg << "Arity Error: expected " << arity()
            << "args, received " << num_args;
    throw std::runtime_error(msg.str());
  }
};

typedef boost::function<std::string()>
Arity0_Func;
typedef boost::function<std::string(std::string const &)> Arity1_Func;

class Function_Impl_Arity0 : public Function
{
public:
  Function_Impl_Arity0(Arity0_Func f) : f_(f) { }
  virtual std::string call() { return f_(); }
  virtual int arity() const { return 0; }
private:
  Arity0_Func f_;
};

class Function_Impl_Arity1 : public Function
{
public:
  Function_Impl_Arity1(Arity1_Func f) : f_(f) { }
  virtual std::string call(
      std::string const & arg1)
  {
    return f_(arg1);
  }
  virtual int arity() const { return 1; }
private:
  Arity1_Func f_;
};

// ========== generator functions ==========

//
// Arity 0
//

template <typename R>
Function::Shptr
make_func(R(*f)())
{
  return Function::Shptr(
      new Function_Impl_Arity0(Arity0_Func(f)));
}

template <typename R, typename C>
Function::Shptr
make_func(
    R(C::*f)(),
    C * c
    )
{
  return Function::Shptr(
      new Function_Impl_Arity0(Arity0_Func(
              boost::bind(f, c))));
}

//
// Arity 1
//

template <typename R, typename T1>
Function::Shptr
make_func(R (*f)(T1))
{
  return Function::Shptr(
      new Function_Impl_Arity1(Arity1_Func(f)));
}

template <typename R, typename C>
Function::Shptr
make_func(
    R(C::*f)() const,
    C * c
    )
{
  return Function::Shptr(
      new Function_Impl_Arity0(Arity0_Func(
              boost::bind(f, c))));
}

//////////////////////////////////////////////////
// Is this possible?
//////////////////////////////////////////////////
template <typename BindT>
Function::Shptr
make_func(
  BindT binder)
{
  // do I create Function_Impl_Arity0
  // or Function_Impl_Arity1? How to decide?
}

So far I'm thinking that the caller is going to have to know the arity
and pass that in as a non-template parameter, and then make a special
flavor of make_func, with specializations for make_func<0> and
make_func<1> to work with bind objects. While that will "work", I'd
rather the compiler determine this rather than require the user to
pass it in.

Thanks!!

Chris


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net