我有一个辅助方法,将boost::function<>类型的对象作为输入,并用另一个处理其他物流的函子包装该函数。

这是我的签名:

class Example {
public:
    typedef ... Callback;

    ...

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

如果尝试将make_wrapper传递给内联调用boost::bind的结果,则会收到有关类型不兼容的编译错误(Apple LLVM版本7.3.0)
class OtherClass {
public:
    void method ( uint32_t );
};

OtherClass* other;

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

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

我发现了两种解决方法:
  • Temp变量:
    boost::function<void( uint32_t )> f = boost::bind( &OtherClass::method, other, _1 );
    Example::Callback c = Example::make_wrapper ( f );
    
  • 调用make_wrapper的特定特化:
    Example::Callback c = Example::make_wrapper<uint32_t> ( boost::bind( &OtherClass::method, other, _1 ) );
    

  • 如果我可以跳过多余的提示并使用内联调用来绑定(bind)make_wrapper,我将更喜欢它。

    有没有一种方法可以声明make_wrapper模板的签名,以帮助编译器找出类型,而无需使用上述变通办法之一?

    最佳答案

    每当使用bind时,都将丢弃有关绑定(bind)函数的参数类型的所有信息。函数模板不可能推断出参数类型T,因为bind的返回值是一个函数对象,可以使用任意数量的任何类型的参数来调用它。

    您可以将bind函数包装到辅助函数模板中,以推断出绑定(bind)的成员函数,尤其是其结果类型和参数(示例使用std::bindstd::function,但我相信可以很容易地将其转换为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));
    }
    

    只要foo::bar不超载,该代码就可以工作,在这种情况下,您无法避免static_cast

    10-08 08:22
    查看更多