c++ - 使用类绑定(bind)功能调用成员函数

标签 c++

如何实现一个非常简单的 boost::bind 版本,它不绑定(bind)参数,但提供了一种在 C++ 类中调用成员函数的方法。

这是我的第一次尝试:

#include <iostream>

struct Foo {
    void x(int i) { std::cout << "Foo " << i << std::endl; }
};

struct Bar {
    void y(int i) { std::cout << "Bar " << i << std::endl; }
};

template<typename A1, typename I, typename M>
struct Binder {
    Binder(I i, M m) : i_(i), m_(m) { }
    void operator()(A1 a1) {
        (i_->*m_)(a1);
    }

    I i_;
    M m_;
};

template<typename A1, typename I, typename M>
Binder<A1, I, M> my_bind(I i, M m) {
    return Binder<A1, I, M>(i, m);
}

int main(int argc, const char *argv[])
{
    Foo foo;
    Bar bar;

    Binder<int, Foo*, void (Foo::*)(int)> b1 = my_bind<int>(&foo, &Foo::x);
    Binder<int, Bar*, void (Bar::*)(int)> b2 = my_bind<int>(&bar, &Bar::y);

    b1(1);
    b2(2);

    return 0;
}

上面的实现确实有效,并且会打印:

Foo 1
Bar 2

问题是 my_bind 的两次调用返回不同类型的对象。我怎样才能改变程序,使 my_bind 返回一个只依赖于 A1 的类型。

最佳答案

The problem is that the two invokes of my_bind returns objects of different types. How can I alter the program, such that my_bind will return a type which only depends on A1.

可以用type erasure来做.

简而言之:

  1. 创建具有您喜欢的界面的抽象类。它可能有一些模板参数。 (以下代码中的 AbstractBinder)
  2. 创建实现此接口(interface)的具体 类。具体类可能比接口(interface)有更多的模板参数。 (下面的 Binder 类)
  3. 使用模板构造器创建Holder 类- 创建Concrete 类,但只存储指向它的Abstract 基类的指针。所以,Holder类只有Abstract接口(interface)需要的模板参数,而它的constructor有Concrete类需要的模板参数。 (下面的 BinderHolder 类)

live demo

用法:

int main()
{
    Foo foo;
    Bar bar;

    BinderHolder<int> b1 = my_bind<int>(&foo, &Foo::x);
    BinderHolder<int> b2 = my_bind<int>(&bar, &Bar::y);

    b1(1);
    b2(2);
}

完整代码:

template<typename A1>
struct AbstractBinder
{
    virtual void call(A1 a1)=0;
    virtual AbstractBinder<A1> *clone()=0;
    virtual ~AbstractBinder(){}
};

template<typename A1, typename I, typename M>
struct Binder : AbstractBinder<A1>
{
    Binder(I i, M m) : i_(i), m_(m) { }
    void call(A1 a1)
    {
        (i_->*m_)(a1);
    }
    virtual AbstractBinder<A1> *clone()
    {
        return new Binder(*this);
    }
    I i_;
    M m_;
};

template<typename A1>
class BinderHolder
{
    AbstractBinder<A1> *ptr;
    BinderHolder &operator=(const BinderHolder&);
public:
    template<typename I, typename M>
    BinderHolder(I i, M m)
        : ptr(new Binder<A1,I,M>(i,m))
    {
    }
    BinderHolder(const BinderHolder &rhs)
        : ptr(rhs.ptr->clone())
    {
    }
    ~BinderHolder()
    {
        delete ptr;
    }
    void operator()(A1 a1)
    {
        ptr->call(a1);
    }
};

template<typename A1, typename I, typename M>
BinderHolder<A1> my_bind(I i, M m) {
    return BinderHolder<A1>(i, m);
}

#include <iostream>

struct Foo {
    void x(int i) { std::cout << "Foo " << i << std::endl; }
};

struct Bar {
    void y(int i) { std::cout << "Bar " << i << std::endl; }
};

int main()
{
    Foo foo;
    Bar bar;

    BinderHolder<int> b1 = my_bind<int>(&foo, &Foo::x);
    BinderHolder<int> b2 = my_bind<int>(&bar, &Bar::y);

    b1(1);
    b2(2);
}

附言如果您确定您的所有 具体 类都具有相同的大小,那么您可以将堆分配替换为放置在固定大小缓冲区内的新内容,并添加 static_assert 以确保安全。

关于c++ - 使用类绑定(bind)功能调用成员函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13103462/

相关文章:

c++ - 毫米 :hh:mm time with c++

c++ - sockaddr_in 获取错误的 IP 地址,cpp

c++ - 排序 char* 数组

c++ - 合并 2 个文件并对它们进行排序

c++ - 在文件中使用 ofstream 时,C6262 堆栈在 C++ 中超出警告

c++ - 我的 char 数组显示的最后几个字符很短。 C++

c++ - 如何将二维数组值与用户输入进行比较?

c++ - std::thread::hardware_concurrency 和静态初始化

c++ - 使用节点和复选框创建 TreeView

c++ - 将任意 lambda 表达式传递给函数?