简体   繁体   中英

How can I make a templated function that takes a parameter that is the result of boost::bind?

I have a helper method that takes as input a boost::function<> type object and wraps the function with another functor that handles some other logistics.

Here is what my signature looks like:

class Example {
public:
    typedef ... Callback;

    ...

    template<typename T>
    static Callback make_wrapper( const boost::function<void( T )>& );
};

If I try to pass make_wrapper the result of calling boost::bind inline I get compilation errors about types being incompatible (Apple LLVM version 7.3.0)

class OtherClass {
public:
    void method ( uint32_t );
};

OtherClass* other;

Example::Callback c = Example::make_wrapper ( boost::bind( &OtherClass::method, other, _1 ) );

this gives:

error: no matching function for call to 'make_wrapper'
note: candidate template ignored: could not match 'function' against 'bind_t'

I have found 2 ways around this:

  1. Temp variable:

     boost::function<void( uint32_t )> f = boost::bind( &OtherClass::method, other, _1 ); Example::Callback c = Example::make_wrapper ( f );
  2. Call specific specialization of make_wrapper:

     Example::Callback c = Example::make_wrapper<uint32_t> ( boost::bind( &OtherClass::method, other, _1 ) );

I would much prefer it if I could skip the extra hinting and call make_wrapper with the inline call to bind.

Is there a way that I can declare the signature of the make_wrapper template to help the compiler figure out the type without needing to use one of workarounds above?

Whenever you use bind you discard all information about the bound function's parameter types. A function template can't possibly deduce the parameter type T , because the return value of bind is a function object that can be called with any number of parameters of any types.

You could wrap the bind function into helper function template to deduce the bound member function and especially its result type and parameters (example uses std::bind and std::function but I believe it can be easily transformed to boost ):

#include <iostream>
#include <string>
#include <functional>

struct foo {
  void bar(int a, std::string s) {
     std::cout << a << " " << s << std::endl;
  }
};


template<typename T1, typename T2>
void make_wrapper(const std::function<void( T1, T2 )>&) {
}

template <class Foo, class Res, class... Args, class... Placeholders>
std::function<Res(Args...)> my_bind(Res (Foo::*bar)(Args...), Foo& f, Placeholders... ps) {
   return std::bind(bar, f, ps...);
}

int main() {
  foo f;
  make_wrapper(my_bind(&foo::bar, f, std::placeholders::_1, std::placeholders::_2));
}

The code will work as long as foo::bar is not overloaded in which case you can't avoid static_cast .

Both std::bind and boost::bind list the return type as unspecified. This means you simply cannot know that, if you want to be at all portable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM