On 1/16/07, Peter Dimov <pdimov@mmltd.net> 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