2016-06-08 105 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

相关问题