将 std::function 绑定到不同对象实例的相同函数
Binding a std::function to the same function of a different object instance
是否可以重新绑定 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::function 的包装器来存储其他信息。
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"。
另外,我认为通过使用更多的元编程魔法,我们可以尝试美化语法。
让我知道这是否适合你。
您的事件处理程序的作用应取决于调用它的实例。因此,从逻辑上讲,解决问题的正确方法是将实例作为参数提供给处理函数,例如
#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
class 的构造函数中正确初始化 handlingFunction
成员,例如通过将其设置为虚拟函数。
下面的代码引入了一个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;
}
我扩展了 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;
}
是否可以重新绑定 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::function 的包装器来存储其他信息。
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"。
另外,我认为通过使用更多的元编程魔法,我们可以尝试美化语法。
让我知道这是否适合你。
您的事件处理程序的作用应取决于调用它的实例。因此,从逻辑上讲,解决问题的正确方法是将实例作为参数提供给处理函数,例如
#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
class 的构造函数中正确初始化 handlingFunction
成员,例如通过将其设置为虚拟函数。
下面的代码引入了一个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;
}
我扩展了 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;
}