std :: bind和boost :: bind技巧

时间:2015-06-02 13:53:20

标签: c++11 boost

#include <functional>
#include <boost/bind.hpp>
class A
{
public:
    A(){}
    ~A(){}
    template<typename _Handler>
    void call_handler(_Handler handler)
    {
        handler();
    }
};

class B
{
public:
    template<typename _Handler>
    void call_handler(_Handler handler)
    {

    }
    template<typename _Handler>
    void run(_Handler handler)
    {
        m_a.call_handler(boost::bind(&B::call_handler<_Handler>, this, handler));
        //only can use boost::bind here
    }
    A m_a;
};
class Test
{
public:
    void handler()
    {

    }
};

int main()
{
    B b;
    Test t;
    b.run(boost::bind(&Test::handler,&t));//only can use std::bind here
}

这是我上面的小测试代码。

我很困惑,我只能按特定顺序使用bind ...请参阅上面的注释

如果我将std :: bind更改为boost :: bind,则编译器失败,反之亦然。

测试:

gcc 4.9.2 for cygwin with option:

g ++ -std = c ++ 11 -fdiagnostics-color = always -fdiagnostics-show-location = every-line -I&#34; / cygdrive / e / opensource libs / boost&#34; main.cpp中

msvc 12.0(visual studio 2013 with update4),默认选项。

gcc诊断消息:

  

包含在/ cygdrive / e / opensource中的文件   库/升压/升压/ bind.hpp:22:0,                    来自main.cpp:3:/ cygdrive / e / opensource libs / boost / boost / bind / bind.hpp:在'void的实例化中   boost :: _ bi :: list2 :: operator()(boost :: _ bi :: type,F&amp;,A&amp ;,,   int)[与F = boost :: _ mfi :: mf1,   boost :: _ bi :: list1&gt; &GT;取代; A =   提高:: _双::列表0; A1 = boost :: _ bi :: value; A2 =   提高:: _双:: bind_t,   boost :: _ bi :: list1&gt; &GT;]”:   / cygdrive / e / opensource libs / boost / boost / bind / bind.hpp:893:50:
  'boost :: _ bi :: bind_t :: result_type需要   boost :: _ bi :: bind_t :: operator()()[with R = void; F =   提高:: _ MFI :: MF1,   boost :: _ bi :: list1&gt; &GT;取代; L =   boost :: _ bi :: list2,boost :: _ bi :: bind_t,   boost :: _ bi :: list1&gt; &GT;取代;   boost :: _ bi :: bind_t :: result_type = void]'main.cpp:12:11:
  'void A :: call_handler(_Handler)[需要_Handler =   提高:: _双:: bind_t,   boost :: _ bi :: list1&gt; &GT; &gt;中   boost :: _ bi :: list2,boost :: _ bi :: bind_t,   boost :: _ bi :: list1&gt; &GT; &GT; &gt;]'main.cpp:27:3:
  从'void B :: run(_Handler)[与_Handler =   提高:: _双:: bind_t,   boost :: _ bi :: list1&gt; &gt;]'main.cpp:44:38:
  从这里需要/ cygdrive / e / opensource   libs / boost / boost / bind / bind.hpp:313:34:错误:无效使用void   表达            unwrapper :: unwrap(f,0)(a [base_type :: a1_],[base_type :: a2_]);                                     ^

msvc 12.0诊断消息:

  

1&gt; ------ Build build:Project:scince_x32,Configuration:Debug   Win32 ------ 1&gt; main.cpp 1&gt; e:\ opensource   libs \ boost \ boost \ bind \ bind.hpp(313):错误C2664:&#39; void   boost :: _ mfi :: mf1 :: operator()(T *,A1)const&#39; :不能   转换参数2来自&#39; void&#39;至   &#39;升压:: _双向:: bind_t,升压:: _双向:: list1的&GT;&GT;&#39;   1 GT;用1> [1>   _Handler =升压:: _双向:: bind_t,升压:: _双向:: list1的&GT;&GT; 1 GT; ,T = B 1> ,A1 = boost :: _ bi :: bind_t,boost :: _ bi :: list1&gt;&gt; 1 GT; ] 1&gt;和1> [1> T =测试* 1> ] 1&gt;类型void的表达式不能   转换为其他类型1&gt; E:\开源   libs \ boost \ boost \ bind \ bind.hpp(893):参见函数参考   模板实例化&#39; void   提高:: _双::列表2,提高:: _双:: bind_t,提振:: _双::列表1&GT;&GT;&GT; ::运算   ()(boost :: _ bi :: type,F&amp;,A&amp;,int)&#39;存在   编译1&gt;用1> [1> T = B * 1> ,
  F =升压:: _ MFI :: MF1,升压:: _双向:: list1的&GT;&GT;&GT; 1 GT; ,A = boost :: _ bi :: list0 1&gt; ] 1&gt; e:\ opensource libs \ boost \ boost \ bind \ bind.hpp(893):参见参考资料   功能模板实例化&#39; void   提高:: _双::列表2,提高:: _双:: bind_t,提振:: _双::列表1&GT;&GT;&GT; ::运算   ()(boost :: _ bi :: type,F&amp;,A&amp;,int)&#39;存在   编译1&gt;用1> [1> T = B * 1> ,
  F =升压:: _ MFI :: MF1,升压:: _双向:: list1的&GT;&GT;&GT; 1 GT; ,A = boost :: _ bi :: list0 1&gt; ] 1&gt; e:\ opensource libs \ boost \ boost \ bind \ bind.hpp(891):编译时   类模板成员函数&#39; void   升压:: _双向:: bind_t,升压:: _双向:: list2中,升压:: _双向:: bind_t,升压:: _双向:: list1的&GT;&GT;&GT;&GT; ::运算   ()(无效)&#39; 1 GT;用1> [1>   _Handler =升压:: _双向:: bind_t,升压:: _双向:: list1的&GT;&GT; 1 GT; ,T = B * 1> ] 1&gt; e:\ c ++ program \ scince_x32 \ scince_x32 \ main.cpp(12):参见参考资料   功能模板实例化&#39; void   升压:: _双向:: bind_t,升压:: _双向:: list2中,升压:: _双向:: bind_t,升压:: _双向:: list1的&GT;&GT;&GT;&GT; ::运算   ()(无效)&#39;正在编译1&gt;用1> [1>   _Handler =升压:: _双向:: bind_t,升压:: _双向:: list1的&GT;&GT; 1 GT; ,T = B * 1> ] 1&gt; e:\ c ++ program \ scince_x32 \ scince_x32 \ main.cpp(27):参见参考资料   类模板实例化   &#39;升压:: _双向:: bind_t,升压:: _双向:: list2中,升压:: _双向:: bind_t,升压:: _双向:: list1的&GT;&GT;&GT;&GT;&#39;   正在编译1&gt;用1> [1>   _Handler =升压:: _双向:: bind_t,升压:: _双向:: list1的&GT;&GT; 1 GT; ,T = B * 1> ] 1&gt; e:\ c ++ program \ scince_x32 \ scince_x32 \ main.cpp(44):参见参考资料   功能模板实例化&#39; void   B ::运行,提高:: _双向:: list1的&GT;&GT;&GT;(_处理程序)&#39;   正在编译1&gt;用1> [1> T =测试*   1 GT; ,
  _Handler =升压:: _双向:: bind_t,升压:: _双向:: list1的&GT;&GT; 1 GT; ]   ==========构建:0成功,1个失败,0个最新,0个跳过==========

1 个答案:

答案 0 :(得分:2)

你(间接)绑定一个绑定表达式作为参数绑定另一个绑定表达式。

在Boost和标准库中,您需要保护内部绑定表达式,以便占位符/绑定不会混合和冲突。

所以它将从

开始
m_a.call_handler(boost::bind(&B::call_handler<_Handler>, this, boost::protect(handler)));

除此之外,protect(handler)包装了该类型且不再_Handler,因此您需要&B::call_handler<???>的其他内容。根据我的经验,迄今为止最简单的方法是使用多态函数对象:

struct handler_caller_f {
    typedef void result_type;

    template <typename H> void operator()(B* /*this_*/, H/* handler*/) const {
        std::cout << __PRETTY_FUNCTION__ << "\n"; 
    }
};

template <typename H> void run(H handler) {
    m_a.call_handler(boost::bind(handler_caller_f(), this, boost::protect(handler)););
}

正如您所看到的,函数对象替换了B::call_handler,并通过再次推断处理程序的类型来解决问题。

这是一个清理过的版本:

使用Boost

<强> Live On Coliru

#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
#include <iostream>

struct A {
    template <typename H> void call_handler(H handler) { 
        handler(); 
    }
};

struct B {
    struct handler_caller_f {
        typedef void result_type;

        template <typename H> void operator()(B* this_, H handler) const {
            handler();
        }
    };

    template <typename H> void run(H handler) {
        m_a.call_handler(boost::bind(handler_caller_f(), this, boost::protect(handler)));
    }

    A m_a;
};

struct Test {
    void handler() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};

int main() {
    Test t;

    B b;
    b.run(boost::bind(&Test::handler, &t));
}

打印

void Test::handler()

使用std::bind

标准图书馆没有protect,但很容易添加:

<强> Live On Coliru

#include <functional>
#include <iostream>

namespace std_ex { // http://stackoverflow.com/questions/18519087/why-is-there-no-stdprotect
template <typename T> struct protect_wrapper : T {
    protect_wrapper(const T &t) : T(t) {}
    protect_wrapper(T &&t) : T(std::move(t)) {}
};

template <typename T>
typename std::enable_if<!std::is_bind_expression<typename std::decay<T>::type>::value, T && >::type protect(T &&t) {
    return std::forward<T>(t);
}

template <typename T>
typename std::enable_if<std::is_bind_expression<typename std::decay<T>::type>::value,
                        protect_wrapper<typename std::decay<T>::type> >::type
protect(T &&t) {
    return protect_wrapper<typename std::decay<T>::type>(std::forward<T>(t));
}
}

struct A {
    template <typename H> void call_handler(H handler) { handler(); }
};

struct B {
    struct handler_caller_f {
        typedef void result_type;

        template <typename H> void operator()(B *this_, H handler) const { handler(); }
    };

    template <typename H> void run(H handler) {
        m_a.call_handler(std::bind(handler_caller_f(), this, std_ex::protect(handler)));
    }

    A m_a;
};

struct Test {
    void handler() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};

int main() {
    Test t;

    B b;
    b.run(std::bind(&Test::handler, &t));
}