我有期望的对象和一个成员函数指针(回调),像这样的框架功能:
do_some_work(Object* optr, void (Object::*fptr)()); // will call (optr->*fptr)()
我如何传递一个lambda表达式呢? 想做somethink是这样的:
class MyObject : public Object
{
void mystuff()
{
do_some_work(this, [](){ /* this lambda I want to pass */ });
}
};
这一切的意义是不是杂乱的MyObject类的接口与回调。
UPD我可以提高do_some_work
绝不是因为我不控制框架,因为它实际上不是一个函数,这儿有数百人。 整个框架是基于该类型的回调。 没有lambda表达式常见的用法例如:
typedef void (Object::*Callback)();
class MyObject : public Object
{
void mystuff()
{
do_some_work(this, (Callback)(MyClass::do_work));
}
void do_work()
{
// here the work is done
}
};
这里的解决方案是基于对马塞洛的回答我的解决方案:
class CallbackWrapper : public Object
{
fptr fptr_;
public:
CallbackWrapper(void (*fptr)()) : fptr_(fptr) { }
void execute()
{
*fptr_();
}
};
class MyObject : public Object
{
void mystuff()
{
CallbackWrapper* do_work = new CallbackWrapper([]()
{
/* this lambda is passed */
});
do_some_work(do_work, (Callback)(CallbackWrapper::execute));
}
};
由于我们创建CallbackWrapper我们可以控制它的生命周期对于其中回调asynchonously使用的情况。 谢谢大家。
这是不可能的。 该构建体(optr->*fptr)()
要求FPTR是一个指针到构件。 如果do_some_work
是你的控制之下,将其更改为拿东西,与lambda函数是兼容的,如std::function<void()>
或参数化类型。 如果它是一个传统的框架,是不是你的控制之下,你可以把它包起来,如果它是一个函数模板,例如:
template <typename Object>
do_some_work(Object* optr, void (Object::*fptr)());
然后,你可以实现一个包装模板:
template <typename F>
void do_some_work(F f) {
struct S {
F f;
S(F f) : f(f) { }
void call() { f(); delete this; }
};
S* lamf = new S(f);
do_some_work(lamf, &S::call);
}
class MyObject // You probably don't need this class anymore.
{
void mystuff()
{
do_some_work([](){ /* Do your thing... */ });
}
};
编辑:如果do_some_work异步完成,你必须分配lamf
在堆上。 我相应的修改上面的代码,只是为了安全起见。 感谢@大卫·罗德里格斯指出这一点。
还有更深层次的问题,您正试图采取比语法错配的方法。 如DeadMG表明,最佳解决方案是提高的界面do_some_work
采取某种(的算符std::function<void()>
在C ++ 11或升压,或甚至一个通用F
在其上operator()
叫做。
通过马塞洛提供的解决方案解决了语法不匹配,但是因为该库由指针采取的第一个元素,这是调用者的责任,以确保在执行回调时,对象将是活着的。 假设回调是异步的,与他的溶液(和其它类似的替代品)的问题在于,在执行回调之前对象可以潜在被破坏,从而导致未定义的行为。
我会建议你使用某种形式的plimp成语中,其中在这种情况下,目标将是隐藏回调的需要(因为实现的其余部分可能并不需要隐藏,你可以只使用另一个类来处理回调,但它存储由值,如果你不想做必须动态地分配更多的内存):
class MyClass;
class MyClassCallbacks {
MyClass* ptr;
public:
MyClassCallbacks( MyClass* ptr ) : ptr(ptr) {}
// callbacks that execute code on `ptr`
void callback1() {
// do some operations
// update *ptr
}
};
class MyClass {
MyClassCallbacks callbackHandler;
public:
void mystuff() {
do_some_work( &callbackHandler, &MyClassHandler::callback1 );
}
};
在这个设计中,两个班分开,而是代表一种独特的单一实体,所以这是很好添加好友声明,让MyClassCallbacks
访问内部数据MyClass
(两者都是一个单一的实体,只划分提供一个简洁的界面但耦合已经很高了,所以通过添加需要选用额外的耦合friend
是没问题的)。
因为之间存在1-1关系MyClass
和MyClassCallbacks
情况下,它们的寿命也必然和就不会有寿命的问题,除了破坏期间。 在破坏你必须确保没有回调注册可踢,而MyClass
对象被销毁。
既然你是怎么做,你可能要多走一英里,并做了适当的平普尔 :将所有由指针保存的数据和实施成不同的类型,并提供MyClass
存储指针,并提供公正公开功能,实现为转发到PIMPL对象。 这可能是你使用的继承和PIMPL方法是有点麻烦的类型层次结构来实现(如果需要扩展以某种方式棘手MyClass
,从获得Object
的平普尔对象可以做,而不是接口类型)。
我不认为你可以做到这一点。 你do_some_work()
被声明为接受指针类的方法Object
,所以这样应该提供。 否则optr->*fptr
是无效的,因为拉姆达是不是成员Object
。 也许你应该尝试使用std::function
和加入所需的成员Object
在其关闭。
您必须使用std::function<void()>
。 两个函数和成员函数指针是高度不适合被回调。