Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C+中的回调+;,模板成员?_C++_Templates_Callback_Pointer To Member - Fatal编程技术网

C++ C+中的回调+;,模板成员?

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)())

下面的代码不起作用,但它很好地表达了我希望做的事情。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)())
    : 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();
}