std :: bind和boost :: bind技巧

玉峰
#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
}

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

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

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

经过测试:

cygwin的gcc 4.9.2,具有以下选项:

g ++ -std = c ++ 11 -fdiagnostics-color = always -fdiagnostics-show-location =每行-I“ / cygdrive / e / opensource libs / boost” main.cpp

带有默认选项的msvc 12.0(带有update4的Visual Studio 2013)。

gcc诊断消息:

在/ cygdrive / e / opensource libs / boost / boost / bind.hpp:22:0包含的文件中,从main.cpp:3:/ cygdrive / e / opensource libs / boost / boost / bind / bind.bind.hpp:在'void boost :: _ bi :: list2 :: operator()的实例化(boost :: _ bi :: type,F&,A&int)[with F = boost :: _ mfi :: mf1,boost :: __ bi :: list1 >>>; A = boost :: _ bi :: list0; A1 = boost :: _ bi :: value; A2 = boost :: _ bi :: bind_t,boost :: __ bi :: list1>>]':/ 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 = boost :: _ mfi :: mf1,boost :: _ bi :: list1>>>; L = boost :: _ bi :: list2,boost :: _ bi :: bind_t,boost :: _ bi :: list1>>>; boost :: _ bi :: bind_t :: result_type = void]'main.cpp:12:11:
需要来自'void A :: call_handler(_Handler)[_Handler = boost :: _ bi :: bind_t,boost :: __ bi :: list1>>>,boost :: _ bi :: list2,boost :: _ bi :: bind_t, boost :: _ bi :: list1
>>>> ] main.cpp:27:3:需要'void B :: run(_Handler)[with _Handler = boost :: _ bi :: bind_t,boost :: _ bi :: list1>>]'main.cpp:44:38:
从此处需要/ cygdrive / e / opensource libs / boost / boost / bind / bind.hpp:313:34:错误:无效使用void表达式unwrapper :: unwrap( f,0)(a [base_type :: a1_],a [base_type :: a2_]); ^

msvc 12.0诊断消息:

1> ------开始构建:项目:scince_x32,配置:调试Win32 ------ 1> main.cpp 1> e:\ opensource libs \ boost \ boost \ bind \ bind.hpp(313) :错误C2664:'void boost :: _ mfi :: mf1 :: operator()(T *,A1)const':无法将参数2从'void'转换为'boost :: _ bi :: bind_t,boost :: _ bi: :list1 >>'1>与1> [1>
_Handler = boost :: _ bi :: bind_t,boost :: _ bi :: list1 >> 1>,T = B 1>,A1 = boost :: _ bi :: bind_t ,boost :: _ bi :: list1 >> 1>] 1>和1> [1> T = Test * 1>] 1> void类型的表达式无法转换为其他类型1> e:\ opensource libs \ boost \ boost \ bind \ bind.hpp(893):请参见对函数模板实例化的引用'void boost :: _ bi :: list2,boost :: _ bi :: bind_t,boost :: _ bi :: list1 >>> :: operator() (boost :: _ bi :: type,F&,A&,int)'被编译为1>并带有1> [1> T = B * 1>,
F = boost :: _ mfi :: mf1,boost :: _ bi :: list1 >>> 1>,A = boost :: _ bi :: list0 1>] 1> e:\ opensource libs \ boost \ boost \ bind \ bind .hpp(893):请参见对函数模板实例化的引用'void boost :: _ bi :: list2,boost :: _ bi :: bind_t,boost :: _ bi :: list1 >>> :: operator()(boost :: _ bi :: type,F&,A&,int)'被编译为1>,其中1> [1> T = B * 1>,
F = boost :: _ mfi :: mf1,boost :: _ bi :: list1 >>> 1>,A = boost :: _ bi :: list0 1>] 1> e:\ opensource libs \ boost \ boost \ bind \ bind.hpp(891):编译类模板成员函数'void boost :: __ bi :: bind_t,boost :: _ bi :: list2,boost :: _ bi :: bind_t,boost :: _ bi :: list1 >>>> :: operator()(void)'1> with 1> [1>
_Handler = boost :: _ bi :: bind_t,boost :: _ bi :: list1 >> 1>,T = B * 1>] 1> e:\ c ++ program \ scince_x32 \ scince_x32 \ main.cpp(12):参见功能模板实例化的参考'void boost :: _ bi :: bind_t,boost :: _ bi :: list2,boost :: _ bi :: bind_t,boost :: _ bi :: list1 >>>> ::: operator()(void )'正在被编译1>与1> [1>
_Handler = boost :: _ bi :: bind_t,boost :: _ bi :: list1 >> 1>,T = B * 1>] 1> e:\ c ++ program \ scince_x32 \ scince_x32 \ main.cpp(27):请参见对类模板实例化'boost :: _ bi :: bind_t,boost :: _ bi :: list2,boost :: _ bi :: bind_t,boost :: __ bi :: list1的引用>>>>'正在被编译1>与1> [1>
_Handler = boost :: _ bi :: bind_t,boost :: _ bi :: list1 >> 1>,T = B * 1>] 1> e:\ c ++ program \ scince_x32 \ scince_x32 \ main.cpp(44):请参阅对函数模板实例化'void B :: run,boost :: __ bi :: list1 >>>(_ Handler)'的引用,正在使用1> [1> T = Test * 1>,
_Handler = boost :: __ bi编译1> :: bind_t,boost :: _ bi :: list1 >> 1>] ==========生成:0成功,1失败,0最新,跳过0 ======= ===

您(间接)绑定一个绑定表达式,该绑定表达式将另一个bind-expression作为参数绑定。

在Boost库和标准库中,您都需要保护内部的bind-expression,以便占位符/绑定不会混合和冲突。

因此,它将开始于

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通过再次推导处理程序的类型来替换和消除问题。

这是一个清理的版本:

使用升压

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));
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

std :: bind和boost :: bind技巧

来自分类Dev

std :: bind和boost :: bind之间的差异

来自分类Dev

std :: bind和功能模板

来自分类Dev

std :: bind和rvalue参考

来自分类Dev

使用std :: bind和std :: function

来自分类Dev

std :: bind和std :: weak_ptr

来自分类Dev

使用 std::bind 和 std::visit

来自分类Dev

澄清使用`boost :: bind`和`this`

来自分类Dev

澄清使用`boost :: bind`和`this`

来自分类Dev

使用boost :: function和boost :: bind

来自分类Dev

使用boost :: function和boost :: bind

来自分类Dev

std :: bind和完美的转发

来自分类Dev

可变参数模板和std :: bind

来自分类Dev

工厂模式和 std::bind 方法

来自分类Dev

boost :: bind连接std :: transform中的字符串

来自分类Dev

在std :: bind和std :: thread中移动语义/行为

来自分类Dev

std :: bind和std :: function重叠还是互补?

来自分类Dev

脚本和从std :: bind到std :: function的转换

来自分类Dev

使用 std::bind 和 std::reference_wrapper::get

来自分类Dev

std :: bind成员函数

来自分类Dev

std :: bind分配给std :: function

来自分类Dev

使用std :: bind调用std :: string方法

来自分类Dev

在std :: bind中省略std :: placeholders

来自分类Dev

std :: bind绑定到std :: array的operator []

来自分类Dev

使用std :: bind分别绑定参数和对象实例

来自分类Dev

C ++ 0x11-std :: bind和composition

来自分类Dev

std :: bind和非虚拟调用基类方法

来自分类Dev

C ++如何结合std :: bind和可变参数元组?

来自分类Dev

std :: bind和非虚拟调用基类方法