我正在尝试实现基本的信号/插槽系统。一切都在运行,但我正在努力提高实施的可用性。
目前,这是您连接信号的方式:
struct X
{
void memberFunction(int a, int b)
{
// do something
}
};
void globalStaticFunction(int a, int b)
{
// do something
}
// this is what the signal::connect function looks like at the moment
ConnectionHandle connect(std::function<RetType(Args...)> func);
int main()
{
// test instance
X x;
// example signal
Signal<void(int, int)> mySignal;
// connect a static function to the signal
mySignal.connect(&globalStaticFunction);
// connect a member function
// here we have to use std::bind to get a std::function
mySignal.connect(std::bind(&X::memberFunction, &x, _1, _2));
}
我想为用户提供一种更简单的绑定成员函数的方法。我有类似的想法(类似于Qt的做法):
// prefered member function connect
// connect(instance_ptr, function_ptr)
mySignal.connect(&x, &X::memberFunction);
是否可以在不使用std :: bind的情况下为成员函数获取std :: function对象?如果没有,是否有一种简单的方法来生成std :: bind调用,仅使用instance_ptr和function_ptr作为成员函数?
答案 0 :(得分:7)
作为Signal
的成员:
template<typename C>
ConnectionHandle connect( C* c, RetType(C::*func)(Args...)) {
return connect( [c,func](Args&&...args) {
return (c->*func)( std::forward<Args>(args)... );
});
}
template<typename C, typename Method, typename... Unused>
ConnectionHandle connect( C* c, Method* m, Unused&&...) {
return connect( [c,func](Args&&...args) {
return (c->*m)( std::forward<Args>(args)... );
});
}
第一次重载使您能够区分重载方法。
第二个,如果第一个失败,则允许您使用与签名兼容的方法。
...
部分确保第一部分匹配得更好(我希望!)
Args&&...
应该使用std::function
,假设std::function
正确完美转发。如果没有,请替换为Args...
。
我认为不需要bind
或变体,因为无论如何我们都会立即将它填入std::function
。创建一个lambda,它们非常适合这项任务。
答案 1 :(得分:3)
类似于这一点可能就是这个伎俩。
首先:制作只与bind
绑定的this
的SIMPLE版本。
template<class T, class RetType, class...Args>
RetType CallMemFn(T* obj, RetType(T::*func)(Args...), Args...args)
{return ((*obj).*(func))(std::forward<Args>(args)...);}
template<class T, class RetType, class...Args>
struct boundthis {
typedef RetType result_type;
typedef T* thistype;
typedef RetType(*signature)(Args...);
boundthis(T* self, RetType(T::*func)(Args...)) :self(self), func(func) {}
RetType operator()(Args...args) {return CallMemFn(self,func,std::forward<Args>(args)...);}
private:
T* self;
RetType(T::*func)(Args...);
};
template<class T, class RetType, class...Args>
boundthis<T,RetType,Args...> bindthis(T* self, RetType(T::*func)(Args...))
{return boundthis<T,RetType,Args...>(self, func);}
最后,你想要的包装:
template<class T, class RetType, class...Args>
ConnectionHandle connect(T* obj, RetType(T::*func)(Args...))
{return connect(std::function<RetType(Args...)>(bindthis(obj, func)));}