[boost.bind] How to retrieve the function type of a boost::bind result
Hi, The following snippet won't compile since the compiler can't deduce the template argument: template<typename T> void foo(boost::function<T> func) { /*...*/ } void bar() {} void baz() { foo(boost::bind(&bar)); // error foo<void()>(boost::bind(&bar)); // OK foo(boost::function<void()>(boost::bind(&bar))); // OK } So how do I get the first line of baz to work? That is, is there a generic way to compute the boost::function type from the bind result? Background code follows here: template<typename T> T getArg(int i) { /*...*/ } template<typename T> struct arity_dispatch; template<> struct arity_dispatch< boost::function<void()> > { static void call(const boost::function<void()>& f) { f(); } }; template<class T> struct arity_dispatch< boost::function<void(T)> > { static void call(const boost::function<void(T)>& f) { f(getArg<T>(0)); } }; template<class T, class U> struct arity_dispatch< boost::function<void(T, U)> > { static void call(const boost::function<void(T, U)>& f) { f(getArg<T>(0), getArg<T>(1)); } }; //aso. template<typename T> void generic_call(boost::function<T> func) { arity_dispatch< boost::function<T> >::call(func); } Neither is it possible for me to call "generic_call" with a boost::bind result nor is it possible to (partial) specialize for the _bi::_bind_t types as these types are internal ones. Also it seems that I can't even statically compute the arity of a boost::bind result (which would indeed help a lot). Any suggestions? If not I propose the introduction of a type function_type in the return type of a bind expression (I already needed it once before). Thanks in advance Olaf Krzikalla
AMDG Olaf Krzikalla wrote:
The following snippet won't compile since the compiler can't deduce the template argument:
template<typename T> void foo(boost::function<T> func) { /*...*/ }
void bar() {}
void baz() { foo(boost::bind(&bar)); // error foo<void()>(boost::bind(&bar)); // OK foo(boost::function<void()>(boost::bind(&bar))); // OK }
So how do I get the first line of baz to work? That is, is there a generic way to compute the boost::function type from the bind result?
There is not because the boost::function type is not unique. Consider: struct F { typedef void result_type; template<class T> void operator()(const T&) const; }; boost::bind(F(), _1); In Christ, Steven Watanabe
Hi, Steven Watanabe wrote:
Olaf Krzikalla wrote:
template<typename T> void foo(boost::function<T> func) { /*...*/ }
void bar() {}
void baz() { foo(boost::bind(&bar)); // error }
So how do I get the first line of baz to work? That is, is there a generic way to compute the boost::function type from the bind result?
There is not because the boost::function type is not unique.
Hmm, indeed. However wouldn't it be possible for the bind (member) function pointer overloads to return a "_bind_t_ex" type derived from _bind_t containing a function_type typedef? In my particular use case I will use bind with function pointers only. Best regards Olaf Krzikalla
Olaf Krzikalla: ...
template<typename T> void foo(boost::function<T> func) { /*...*/ }
void bar() {}
void baz() { foo(boost::bind(&bar)); // error }
So how do I get the first line of baz to work? That is, is there a generic way to compute the boost::function type from the bind result?
There is not because the boost::function type is not unique. Hmm, indeed. However wouldn't it be possible for the bind (member) function pointer overloads to return a "_bind_t_ex" type derived from _bind_t containing a function_type typedef? In my particular use case I will use bind with function pointers only.
In general you can't deduce a boost::function<> from the result of bind, even if you only use functions. function<void()> f1 = bind( bar ); // OK function<void(string)> f2 = bind( bar ); // OK function<void(int,int)> f3 = bind( bar ); // still OK In fact, this ability to ignore arguments is the primary reason to use bind(bar), if you didn't need it, you could have used just bar.
Olaf Krzikalla:
template<class T, class U> struct arity_dispatch< boost::function<void(T, U)> > { static void call(const boost::function<void(T, U)>& f) { f(getArg<T>(0), getArg<T>(1)); } };
Why not dispatch on the number of arguments that are available via getArg? You won't then need to know the arity of the function object (assuming it has one and only one arity, which it may not.)
Why not dispatch on the number of arguments that are available via getArg? You won't then need to know the arity of the function object (assuming it has one and only one arity, which it may not.) I'm not sure if I understand you right. The top level problem is to bind C++ functions in a generic way to LUA
Hi, Peter Dimov wrote: script callbacks. That is I know the actual number of arguments not before runtime. Below is my current solution (LUA specific stuff and the rather obvious ArgTypeDispatcher are stripped): ---snip--- template<class T> struct ArgNumDispatcher; template<> struct ArgNumDispatcher<boost::function<void()> > { static void doFunction(const boost::function<void()>& f) { f(); } }; template<class T> struct ArgNumDispatcher<boost::function<void(T)> > { static void doFunction(const boost::function<void(T)>& f) { f(ArgTypeDispatcher<T, 0>::get()); } }; template<class T, class U> struct ArgNumDispatcher<boost::function<void(T, U)> > { static void doFunction(const boost::function<void(T, U)>& f) { f(ArgTypeDispatcher<T, 0>::get(), ArgTypeDispatcher<U, 1>::get()); } }; // aso. struct tFunctionBase { virtual void doFunction() = 0; }; template<class T> struct tFunction : tFunctionBase { tFunction(const T& f) : func(f) {} virtual void doFunction() { int iNumArgs = getNumArguments(); //comes from LUA if (T::arity != iNumArgs) { //some error handling } ArgNumDispatcher<T>::doFunction(func); } T func; }; std::map<std::string, boost::shared_ptr<tFunctionBase> > m_Functions; template<class T> void registerFunction(const std::string& strName, boost::function<T> func) { boost::shared_ptr<tFunctionBase> p (new tFunction<boost::function<T> >(func)); m_Functions.insert(std::make_pair(strName, p)); } ---snip--- This works pretty well so far. However I can't squeeze out this last bit of elegance by calling registerFunction with a bind expression and without explicitely stating the function type in the template parameter. But maybe there is a completely dfferent approach I don't see yet(?). Thanks in advance Olaf Krzikalla
participants (3)
-
Olaf Krzikalla
-
Peter Dimov
-
Steven Watanabe