如何实现一个非常简单的 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来做.
简而言之:
- 创建具有您喜欢的界面的抽象类。它可能有一些模板参数。 (以下代码中的 AbstractBinder)
- 创建实现此接口(interface)的具体 类。具体类可能比接口(interface)有更多的模板参数。 (下面的 Binder 类)
- 使用模板构造器创建Holder 类- 创建Concrete 类,但只存储指向它的Abstract 基类的指针。所以,Holder类只有Abstract接口(interface)需要的模板参数,而它的constructor有Concrete类需要的模板参数。 (下面的 BinderHolder 类)
用法:
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/