c++回调——如何解耦回调类型
C++ Callback -- How to decouple the call back type
例如,下面的伪代码中,类B需要通过B::m_cb成员调用A::Action()
我们的目标是,如何创建一个通用的,非模板的Callback类,这样"B"就不必是模板,而" Callback "可以保存任何类型的函数签名。
我以前用过这样的代码,但是现在我找不到那个实现。我只记得:
- "CallBack"本身不是模板,但它包含成员模板
辅助函数模板make_callback将实例化CallBack对象
谁能给个指针?
Class A
{
public:
void Action(){//...};
};
class CallBack
{
//...
// CallBack it self it is a NOT a template
// It can wrap member template though
};
class B
{
public:
void SetCallback(CallBack to){
m_cb = to;
}
void do_something()
{
//...
m_cb.Execute();
//...
}
private:
CallBack m_cb;
};
int main()
{
A obj1;
CallBack cb = make_callback(&obj1, &A::Action);
B obj2;
obj2.SetCallback(cb);
//....
obj2.do_something();
}
这是我从这个网站得到的样本代码。我试着改进了一下,让它可以容忍任意回调函数的返回类型。但是它仍然不能像第18行那样处理任意数量的参数。另外,T是指向成员函数的指针,它应该依赖于c。我不知道如何强制执行。
#include <iostream>
#include <memory>
// INTERNAL CLASSES
class CallbackSpecBase
{
public:
virtual ~CallbackSpecBase() {}
virtual void operator()(...) const = 0;
};
template<class C, class T>
class CallbackSpec : public CallbackSpecBase
{
public:
CallbackSpec(C& o, T m) : obj(o), method(m) {}
/*line 18*/ void operator()(...) const { (&obj->*method)(); } // how to pass "..." into method(...)
private:
C& obj;
T method;
};
// PUBLIC API
class Callback
{
public:
Callback() {}
void operator()() { (*spec)(); }
template<class C, class T>
void set(C& o, T m) { spec.reset(new CallbackSpec<C, T>(o, m)); }
private:
std::auto_ptr<CallbackSpecBase> spec;
};
// TEST CODE
class Test
{
public:
void foo() { std::cout << "Working" << std::endl; }
void bar() { std::cout << "Like a charm" << std::endl; }
};
int main()
{
Test t;
Callback c;
c.set(t, &Test::foo);
c();
c.set(t, &Test::bar);
c();
}
你要找的是std::function
(c++ 0x)/boost::function
。它们使用类型擦除使函数像一级对象一样。你可以这样做:
class A
{
public:
void Action() {//...};
};
class B
{
public:
template <typename Func>
void SetCallback(Func func) {
m_cb = func;
}
void do_something() {
m_cb(); // whatever function
}
private:
std::function<void()> m_cb; // anything callable with no arguments
};
int main()
{
A obj1;
B obj2;
obj2.SetCallback(make_callback(&obj1, &A::Action));
// or:
obj2.SetCallback(std::bind(&obj1, &A::Action)); // or boost::bind
obj2.do_something();
}
我基于本文实现了一个回调机制:
http://www.codeproject.com/KB/cpp/CPPCallback.aspx 通过该实现,您可以使用全局函数、静态成员函数或非静态成员函数作为回调。本文描述了如何为所有这些类型创建委托对象作为函函数。你的class B
可以有一个委托对象作为成员,一个注册回调函数的方法和一个调用它的方法。class B
和回调函数都不需要模板化!委托对象包含一个对象指针(如果使用非静态成员函数作为回调)和一个指向模板化静态包装函数的指针。在这个包装函数中存储了指向回调函数的函数指针。可以直接调用,也可以在绑定到传递的对象指针之前调用。
class B
{
public:
void SetCallback(CDelegate f_Delegate)
{
m_Delegate = f_Delegate;
}
static void do_something()
{
//...
m_Delegate();
//...
}
private:
static CDelegate m_Delegate;
};
更新:
机制也描述在这里:5年后,还有比"最快的c++委托"更好的东西吗?
这并没有真正回答你的问题,因为回调必须是一个模板,除非你想通过void*
传递一个参数(在我看来这是一个完全疯狂的想法)。
其中一个答案给出了一个完整的解决方案:
#include <memory>
template< typename R, typename ... Args >
class CallbackBase
{
public:
typedef std::shared_ptr< CallbackBase< R, Args... > >
CallbackPtr;
virtual ~CallbackBase()
{
}
virtual R Call( Args ... args) = 0;
};
template< typename R, typename ... Args >
class FunctionCallback : public CallbackBase< R, Args... >
{
public:
typedef R (*funccb)(Args...);
FunctionCallback( funccb cb_ ) :
CallbackBase< R, Args... >(),
cb( cb_ )
{
}
virtual ~FunctionCallback()
{
}
virtual R Call(Args... args)
{
return cb( args... );
}
private:
funccb cb;
};
template < typename R, typename ...Args >
typename CallbackBase< R, Args... >::CallbackPtr
MakeCallback( R (*cb)(Args...) )
{
typename CallbackBase< R, Args... >::CallbackPtr
p( new FunctionCallback< R, Args... >( cb )
);
return p;
}
bool Foo_1args( const int & t)
{
return true;
}
int main()
{
auto cbObj = MakeCallback( & Foo_1args );
}
希望有帮助。如果你讨厌模板,你可以使用typedef。
- 架构决策:返回std::future还是提供回调
- 正在为Xtensa simcall函数编写回调函数
- 如何在C++中使用非静态成员函数作为回调函数
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 用于在回调中调用解析器的设计模式
- 如何使用C++对象的成员函数作为 C 样式回调?
- Java从C++回调到C++回调
- 如何将成员函数作为回调参数传递给需要"typedef-ed"自由函数指针的函数?
- 从不同的 cpp 调用回调函数会导致bad_function_call
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 不带轮询的 SDL2 事件回调
- C++存储带有可变参数的回调
- 如何使用 Node-addon-API 实现 node-nan 回调
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 访问类C++ C 样式回调
- 处理类内的回调时,必须调用对非静态成员函数的引用
- 如果 C 函数仍然可以间接执行(通过回调函数),那么将它声明为静态函数是否是一种不好的做法?
- c++回调——如何解耦回调类型
- 将签名来自元组解包的静态方法的地址作为回调传递