2016-06-08 106 views
4

是否可以重新綁定std :: function以指向相同的函數,但使用不同的對象實例?將std :: function綁定到不同對象實例的相同函數

說如果我有一個對象具有綁定到另一個函數的std :: function,但是如果該對象被複制到另一個實例,我想重新將std :: function重新綁定到該新實例的舊例。

#include "stdafx.h" 
#include <iostream> 
#include <functional> 

class EventHandler 
{ 
public: 
    int Num; 
    std::function<int()> OnEvent; 

    EventHandler (int inNum) 
    { 
     Num = inNum; 
    } 

    EventHandler (const EventHandler& other) 
    { 
     Num = other.Num; 
     OnEvent = other.OnEvent; //TODO: Need some way to redirect the std::function to the new instance rather than having the delegate point to the original object's handler. 
    } 

    int HandleEvent() 
    { 
     return Num; 
    } 
}; 

int main() 
{ 
    EventHandler a(4); 
    a.OnEvent = std::bind(&EventHandler::HandleEvent, a); 
    EventHandler b(a); 
    b.Num = 5; 
    //Uncommenting the line below is a manual way of redirecting event handler to the new instance. 
    //b.OnEvent = std::bind(&EventHandler::HandleEvent, b); 

    int aResult = a.OnEvent(); 
    int bResult = b.OnEvent(); 

    //This will print out 4 and 4 instead of 4 and 5 since b is still bound to a's event handler. 
    std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n'; 

    return 0; 
} 

我打算有一個std ::函數的包裝來存儲附加信息。

+0

是問題怎麼做這個事情具體,或者是如何讓這個概念在代碼中工作?我的意思是,還有其他方法可以正確獲取EventHandler設置。例如,構造函數可以只是std :: bind(&EventHandler :: HandleEvent,this);.還有其他選擇,但我不清楚你的目標。 – tmruss

+0

更多關於如何讓這個概念在代碼中工作。我想我可能爲了清晰起見而簡化了這個例子。我正在使用的實際代碼庫與對象具有父子關係。當父母被複制時,其子女也被複制。我需要遷移孩子的std ::函數來指向新的實例,而不是指向原件。 –

+0

讓我先說這個,說我可能會嘗試找到一種不同的方式來組織事情,然後用我將要說的來解決這個問題。這聽起來像是一個設計問題,可能有一個更簡單的解決方案。然而,你可以創建一個模板包裝器,存儲一個指向成員的指針,該指針將被綁定到函數中。然後,在您的賦值運算符中,您使用指向成員的指針作爲目標,將「this」作爲實例進行綁定。 做到這一點的唯一原因是,如果你試圖使它通用。如果它總是相同的功能,我會重新綁定它。 – tmruss

回答

1

下面的代碼引入了一個binding_function<R(Args...)>,它被稱爲function<R()>,參數在構建後可以隨時重新綁定(假設它不是nullptr)。

#include <functional> 
#include <tuple> 
#include <utility> 
#include <memory> 
#include <iostream> 

template <typename T> 
class binding_function; 

template <typename R, typename... Args> 
class binding_function<R(Args...)> : std::function<R()> 
{ 
    using base_function = std::function<R(Args...)>; 
    using binded_function = std::function<R()>; 
    base_function base; 

public: 
    binding_function() = default; 

    template <typename BaseF, typename... TArgs> 
    binding_function(BaseF&& f, TArgs&&... args) 
    : base(std::forward<BaseF>(f)) { 
    rebind(std::forward<TArgs>(args)...); 
    } 

    template <typename... TArgs> 
    void rebind(TArgs&&... args) 
    { 
    static_cast<binded_function&>(*this) = 
     std::bind(base, std::forward<TArgs>(args)...); 
    } 

    using binded_function::operator(); 
}; 

class EventHandler 
{ 
public: 
    // change type of OnEvent to binding_function 
    binding_function<int(EventHandler)> OnEvent; 

    // others remain the same 
}; 

int main() 
{ 
    EventHandler a(4); 

       // first binding 
    a.OnEvent = {&EventHandler::HandleEvent, a}; 
    EventHandler b(a); 
    b.Num = 5; 
    b.OnEvent.rebind(b); // rebinding 

    int aResult = a.OnEvent(); 
    int bResult = b.OnEvent(); 

    //This will print out 4 and 4 instead of 4 and 5 since b is still bound to a's event handler. 
    std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n'; 

    return 0; 
} 
+0

我還有很多東西要學。我不知道std :: Forward和'using'關鍵字。 我不完全理解第一個類定義'binding_function',但它是由於某種原因需要的。我還在研究這個代碼,直到我得到這個時刻。 雖然這段代碼的確很好用! –

+0

@DW_Ant [在類定義中使用'](http://en.cppreference.com/w/cpp/language/using_declaration#In_class_definition)['使用'類​​型別名](http://en.cppreference.com/ w/cpp/language/type_alias)['std :: forward'](http://en.cppreference.com/w/cpp/utility/forward) – user1887915

+0

如果有問題的函數有自己的參數? – veio

0

AFAIK你問什麼是不可能的,但我覺得有一種變通方法,你可以這樣做:

class EventHandler 
{ 
public: 
    int Num; 
    std::function<int()> OnEvent; 

    template <typename Func> 
    EventHandler (int inNum, Func on_event) 
    { 
     Num = inNum; 
     OnEvent = [=]() { return (this->*on_event)(); }; 
    } 

    EventHandler (const EventHandler& other): EventHandler(other.Num, &EventHandler::HandleEvent) {} 

    int HandleEvent() 
    { 
     return Num; 
    } 
}; 

int main() 
{ 
    EventHandler a(4, &EventHandler::HandleEvent); 
    EventHandler b(a); 
    b.Num = 5; 

    int aResult = a.OnEvent(); 
    int bResult = b.OnEvent(); 

    //This will print out 4 and 4 instead of 4 and 5 since b is still bound to a's event handler. 
    std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n'; 

    return 0; 
} 

這版畫「aResult = 4 bResult = 5」爲你想要的。另外,我認爲通過使用更多元編程魔法,我們可以嘗試對語法進行優化。

讓我知道這是否適合你。

+0

另外,如果其要求是能夠指向常規功能,它應該是可能的帶着幾分使用標籤調度的幫助。 – Arunmu

1

你的事件處理函數應該依賴於它被調用的實例。因此,在邏輯上,解決該問題的正確方法是將該實例作爲處理函數的參數提供,例如,

#include <iostream> 
#include <functional> 

class EventHandler 
{ 
private: 
    std::function<int(EventHandler &)> handlingFunction; 

public: 
    int Num; 

    EventHandler (int inNum) 
    : handlingFunction ([] (EventHandler &) -> int { throw 0; }) 
    , Num (inNum) 
    { } 

    void SetHandlingFunction (std::function<int(EventHandler &)> f) { 
    handlingFunction = f; 
    } 

    // for convenience, if the handling function is a member 
    void SetHandlingFunction (int EventHandler::*mf()) { 
     handlingFunction = 
     [mf] (EventHandler & myself) -> int { return myself.*mf(); } 
     ; 
    } 

    int OnEvent() { 
    return handlingFunction (*this); 
    } 

    int HandleEvent() 
    { 
    return Num; 
    } 
}; 

int main() 
{ 
    EventHandler a(4); 
    a.SetHandlingFunction ([] (EventHandler & h) -> int { return h.HandleEvent(); }); 

    // or 
    a.SetHandlingFunction (&EventHandler::HandleEvent); 

    EventHandler b(a); 
    b.Num = 5; 

    int aResult = a.OnEvent(); 
    int bResult = b.OnEvent(); 

    std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n'; 

    return 0; 
} 

當然,如果你的處理函數總是是一個成員函數,你可以簡單地通過指針到成員函數替換std::function

請注意,您應該在EventHandler類的構造函數中正確初始化handlingFunction成員,例如,通過將其設置爲虛擬功能。

1

我伸出user1887915的答案,讓功能與參數:

#include <functional> 
#include <tuple> 
#include <utility> 
#include <memory> 
#include <iostream> 

template <typename T> 
class binding_function; 

template <typename R, typename... Args, typename SelfType> 
class binding_function<R(SelfType, Args...)> : std::function<R(Args...)> 
{ 
    using base_function = std::function<R(SelfType, Args...)>; 
    using binded_function = std::function<R(Args...)>; 
    base_function base; 

public: 
    binding_function() = default; 

    template <typename BaseF, typename... TArgs> 
    binding_function(BaseF&& f, SelfType t, TArgs&&... args) 
    : base(std::forward<BaseF>(f)) { 
    rebind(std::forward<SelfType>(t), std::forward<TArgs>(args)...); 
    } 

    template <typename T, typename... TArgs> 
    void rebind(T&& t, TArgs&&... args) 
    { 
    static_cast<binded_function&>(*this) = 
     std::bind(base, std::forward<SelfType>(t), std::forward<TArgs>(args)...); 
    } 

    using binded_function::operator(); 
}; 



class EventHandler 
{ 
public: 
    int Num; 
    binding_function<int(EventHandler, int)> OnEvent; 


    EventHandler (int inNum) 
    { 
     Num = inNum; 
    } 

    EventHandler (const EventHandler& other) 
    { 
     Num = other.Num; 
     OnEvent = other.OnEvent; //TODO: Need some way to redirect the std::function to the new instance rather than having the delegate point to the original object's handler. 
    } 
    int HandleEvent (int value) 
    { 
     return Num + value; 
    } 
}; 
int main() 
{ 
    EventHandler a(4); 

       // first binding 
    a.OnEvent = {&EventHandler::HandleEvent, a, std::placeholders::_1}; 
    EventHandler b(a); 
    b.Num = 5; 
    b.OnEvent.rebind(b, std::placeholders::_1); // rebinding 

    int aResult = a.OnEvent(1); 
    int bResult = b.OnEvent(1); 

    //This will print out 4 and 4 instead of 4 and 5 since b is still bound to a's event handler. 
    std::cout << "aResult=" << aResult << " bResult=" << bResult << '\n'; 

    return 0; 
} 
+0

如果我在複製構造函數中調用rebind,bind函數再次調用複製構造函數,這會導致無限遞歸。有人知道如何解決這個問題嗎? – veio

相關問題