C++ C+中的回调+;,模板成员?
下面的代码不起作用,但它很好地表达了我希望做的事情。template struct容器有一个问题,我认为它应该可以工作,因为任何模板参数都知道它的大小C++ C+中的回调+;,模板成员?,c++,templates,callback,pointer-to-member,C++,Templates,Callback,Pointer To Member,下面的代码不起作用,但它很好地表达了我希望做的事情。template struct容器有一个问题,我认为它应该可以工作,因为任何模板参数都知道它的大小 class callback { public: // constructs a callback to a method in the context of a given object template<class C> callback(C& object, void (C::*method)())
class callback {
public:
// constructs a callback to a method in the context of a given object
template<class C>
callback(C& object, void (C::*method)())
: ptr.o(object), ptr.m(method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
template<class C>
struct {
C& o;
void (C::*m)();
} ptr;
};
类回调{
公众:
//在给定对象的上下文中构造对方法的回调
模板
回调(C&对象,void(C::*方法)()
:ptr.o(对象),ptr.m(方法){}
//调用该方法
void运算符()(){
(&ptr.o->*ptr.m)();
}
私人:
//指针指向方法的容器
模板
结构{
C&o;
无效(C::*m)();
}ptr;
};
有没有办法做这样的事?我的意思是有一个非模板类回调,它封装了任何指向方法的指针
<谢谢C++大师!
编辑:
请看这个:
你没有说你发现了什么错误,但我发现这是有效的:
template<typename C>
class callback {
public:
// constructs a callback to a method in the context of a given object
callback(C& object, void (C::*method)())
: ptr(object,method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
// template<class C>
struct Ptr{
Ptr(C& object, void (C::*method)()): o(object), m(method) {}
C& o;
void (C::*m)();
} ptr;
};
模板
类回调{
公众:
//在给定对象的上下文中构造对方法的回调
回调(C&对象,void(C::*方法)()
:ptr(对象、方法){}
//调用该方法
void运算符()(){
(&ptr.o->*ptr.m)();
}
私人:
//指针指向方法的容器
//模板
结构Ptr{
Ptr(C&object,void(C::*method)():o(object),m(method){}
C&o;
无效(C::*m)();
}ptr;
};
注意,Ptr需要一个构造函数,因为它有一个引用成员
您可以不使用struct Ptr,而使用原始成员
使用VS2008 express进行测试。您需要使用多态性。将抽象基类与虚拟调用方法(
operator()
如果您愿意),以及使用正确类型签名实现虚拟方法的模板化子体一起使用
按照现在的方式,保存类型的数据是模板化的,但用于调用方法并传递对象的代码不是。那是行不通的;模板类型参数需要经过构造和调用。@Barry Kelly
#include <iostream>
class callback {
public:
virtual void operator()() {};
};
template<class C>
class callback_specialization : public callback {
public:
callback_specialization(C& object, void (C::*method)())
: o(object), m(method) {}
void operator()() {
(&o ->* m) ();
}
private:
C& o;
void (C::*m)();
};
class X {
public:
void y() { std::cout << "ok\n"; }
};
int main() {
X x;
callback c(callback_specialization<X>(x, &X::y));
c();
return 0;
}
#包括
类回调{
公众:
虚空运算符()({});
};
模板
类回调\u专门化:公共回调{
公众:
回调(C&object,void(C::*方法)()
:o(对象),m(方法){}
void运算符()(){
(&o->*m)();
}
私人:
C&o;
无效(C::*m)();
};
X类{
公众:
void y(){std::cout改进OP的答案:
int main() {
X x;
callback_specialization<X> c(x, &X::y);
callback& ref(c);
c();
return 0;
}
intmain(){
X;
回调函数c(x,&x::y);
回调&ref(c);
c();
返回0;
}
这个打印“ok”
在VS2008 express上测试。我最近实现了以下功能:
#define UNKOWN_ITEM 0xFFFFFFFF
template <typename TArg>
class DelegateI
{
public:
virtual void operator()(TArg& a)=0;
virtual bool equals(DelegateI<TArg>* d)=0;
};
template <class TArg>
class Event
{
public:
Event()
{
}
~Event()
{
for (size_t x=0; x<m_vDelegates.size(); x++)
delete m_vDelegates[x];
}
void operator()(TArg& a)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
m_vDelegates[x]->operator()(a);
}
}
void operator+=(DelegateI<TArg>* d)
{
if (findInfo(d) != UNKOWN_ITEM)
{
delete d;
return;
}
m_vDelegates.push_back(d);
}
void operator-=(DelegateI<TArg>* d)
{
uint32 index = findInfo(d);
delete d;
if (index == UNKOWN_ITEM)
return;
m_vDelegates.erase(m_vDelegates.begin()+index);
}
protected:
int findInfo(DelegateI<TArg>* d)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
if (m_vDelegates[x]->equals(d))
return (int)x;
}
return UNKOWN_ITEM;
}
private:
std::vector<DelegateI<TArg>*> m_vDelegates;
};
template <class TObj, typename TArg>
class ObjDelegate : public DelegateI<TArg>
{
public:
typedef void (TObj::*TFunct)(TArg&);
ObjDelegate(TObj* t, TFunct f)
{
m_pObj = t;
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
ObjDelegate<TObj,TArg> *d = dynamic_cast<ObjDelegate<TObj,TArg>*>(di);
if (!d)
return false;
return ((m_pObj == d->m_pObj) && (m_pFunct == d->m_pFunct));
}
virtual void operator()(TArg& a)
{
if (m_pObj && m_pFunct)
{
(*m_pObj.*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
TObj* m_pObj; // pointer to object
};
template <typename TArg>
class FunctDelegate : public DelegateI<TArg>
{
public:
typedef void (*TFunct)(TArg&);
FunctDelegate(TFunct f)
{
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
FunctDelegate<TArg> *d = dynamic_cast<FunctDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pFunct == d->m_pFunct);
}
virtual void operator()(TArg& a)
{
if (m_pFunct)
{
(*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
};
template <typename TArg>
class ProxieDelegate : public DelegateI<TArg>
{
public:
ProxieDelegate(Event<TArg>* e)
{
m_pEvent = e;
}
virtual bool equals(DelegateI<TArg>* di)
{
ProxieDelegate<TArg> *d = dynamic_cast<ProxieDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pEvent == d->m_pEvent);
}
virtual void operator()(TArg& a)
{
if (m_pEvent)
{
(*m_pEvent)(a);
}
}
Event<TArg>* m_pEvent; // pointer to member function
};
template <class TObj, class TArg>
DelegateI<TArg>* delegate(TObj* pObj, void (TObj::*NotifyMethod)(TArg&))
{
return new ObjDelegate<TObj, TArg>(pObj, NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(void (*NotifyMethod)(TArg&))
{
return new FunctDelegate<TArg>(NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(Event<TArg>* e)
{
return new ProxieDelegate<TArg>(e);
}
触发:
someEvent(someClassObj);
您也可以创建自己的委托并覆盖它们所做的事情。我还创建了一些其他委托,其中一个委托能够确保事件触发gui线程中的函数,而不是它所调用的线程。请参见此图
这是一个完整的工作示例,它实现了我认为您正在尝试的功能:
#include <iostream>
#include <memory>
// INTERNAL CLASSES
class CallbackSpecBase
{
public:
virtual ~CallbackSpecBase() {}
virtual void operator()() const = 0;
};
template<class C>
class CallbackSpec : public CallbackSpecBase
{
public:
CallbackSpec(C& o, void (C::*m)()) : obj(o), method(m) {}
void operator()() const { (&obj->*method)(); }
private:
C& obj;
void (C::*method)();
};
// PUBLIC API
class Callback
{
public:
Callback() {}
void operator()() { (*spec)(); }
template<class C>
void set(C& o, void (C::*m)()) { spec.reset(new CallbackSpec<C>(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();
}
#包括
#包括
//内部类
类CallbackSpecBase
{
公众:
虚拟~CallbackSpecBase(){}
虚空运算符()()常量=0;
};
模板
类CallbackSpec:public CallbackSpecBase
{
公众:
CallbackSpec(C&o,void(C::*m)():obj(o),方法(m){}
void操作符()()常量{(&obj->*方法)(;}
私人:
C&obj;
无效(C::*方法)();
};
//公共API
类回调
{
公众:
回调(){}
void操作符(){(*spec)(;}
模板
void集(C&o,void(C::*m)(){spec.reset(newcallbackspec(o,m));}
私人:
标准::自动ptr规范;
};
//测试代码
课堂测试
{
公众:
void foo(){std::cout该类型不会是多态的,我假设这主要是练习的重点,然后你会做得很好。但是现在回调是一个模板……没有回调模板是有办法的吗?也必须考虑对象切片等等。最好通过指针存储数据。方法,它被定义为不做任何事情。为什么它应该做任何事情?它是虚拟的,它不应该调用回调\u专门化版本吗?至少这是我想要做的…它被称为切片-你用一个更大的派生对象初始化一个“回调”,所以你会丢失额外的位。你可以尝试初始化一个回调&从你的专门化不,不应该这样-对象c是callback类型,因此您得到callbacks操作符()。虚拟方法只能通过指针或引用工作。您希望使用boost::function
或boost::signal
:。它需要是一个模板,以便只允许能够处理该类型对象的代理注册。啊,我理解了,非常感谢。但是在代理函数中有一些新的动态分配。P请看我的另一个问题:是的,我知道,这是我唯一不满意的一点,但它避免了复制对象,最终用户也不需要知道。如果你有更好的方法不用复制,请告诉我。请看我的另一个问题…也许有人知道更好的方法:-)Thansk再次提出你非常好的答案。看到这个:Y很酷的回答,可惜我不能选择其中两个是最好的…但你有一些动态分配。看到了吗
Event<SomeClass> someEvent;
someEvent += delegate(&someFunction);
someEvent += delegate(classPtr, &class::classFunction);
someEvent += delegate(&someOtherEvent);
someEvent(someClassObj);
#include <iostream>
#include <memory>
// INTERNAL CLASSES
class CallbackSpecBase
{
public:
virtual ~CallbackSpecBase() {}
virtual void operator()() const = 0;
};
template<class C>
class CallbackSpec : public CallbackSpecBase
{
public:
CallbackSpec(C& o, void (C::*m)()) : obj(o), method(m) {}
void operator()() const { (&obj->*method)(); }
private:
C& obj;
void (C::*method)();
};
// PUBLIC API
class Callback
{
public:
Callback() {}
void operator()() { (*spec)(); }
template<class C>
void set(C& o, void (C::*m)()) { spec.reset(new CallbackSpec<C>(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();
}