2012-10-27 92 views
1

如何實現一個非常簡單的boost :: 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的類型。

+0

我想你最好使用'std :: mem_fn()'。 ...或者你是否願意綁定參數,例如對象? –

+0

我已經開始着手這方面的工作,因爲需要它在嵌入式應用程序中,其中C++環境不支持異常或標準庫。所以,std :: men_fn在我的目標系統上不是aviable ... – Allan

+0

當我想到這個時,它更多的是boost ::函數實現我需要了解 – Allan

回答

0

問題是,兩次調用my_bind會返回不同類型的對象。我怎樣才能改變程序,使my_bind將返回一個只取決於A1的類型。

這可能與type erasure有關。

簡而言之:

  1. 與你喜歡的界面創建摘要類。它可能有一些模板參數。 (以下代碼中的AbstractBinder)
  2. 創建具體實現此接口的類。具體類可能比接口具有更多的模板參數。 (以下粘合劑類)
  3. 創建持有人類模板的構造 - 它創建混凝土類,但只存儲指針,它的基礎摘要類。所以,持有者類只具有抽象接口所需的模板參數,而其構造函數具有所需的所有其餘模板參數具體類。 (下面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); 
} 

P.S.如果您確定所有類都具有相同的大小,那麼您可以將堆內分配替換爲固定大小的緩存,並添加static_assert以確保安全。