Pregunta

Después de código no funciona, sino que expresa bien lo que deseo hacer. Hay un problema con el contenedor plantilla de estructura, que creo que debería funcionar debido a que su tamaño es conocido por cualquier parámetro de plantilla.

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;

};

¿Hay alguna manera de hacer tal cosa? Me refiero a tener una devolución de llamada clase no molde que envuelve cualquier puntero a método?

Gracias C ++ gurús!

Editar

Por favor, vea la siguiente:

de devolución de llamada en C ++, miembro de plantilla? (2)

¿Fue útil?

Otros consejos

Este es un ejemplo de trabajo completo que hace lo que yo creo que está tratando de hacer:

#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();
}

Recientemente he implementado esto:

#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);
}

usarlo de esta manera:

definir:

Event<SomeClass> someEvent;

contar con devoluciones de llamada:

someEvent += delegate(&someFunction);
someEvent += delegate(classPtr, &class::classFunction);
someEvent += delegate(&someOtherEvent);

gatillo:

someEvent(someClassObj);

También puede hacer sus propios delegados y overide lo que hacen. Hice un par de otros con un ser capaz de asegurarse de que el evento activa la función en el hilo de interfaz gráfica de usuario en lugar de la rosca que se llamaba.

Es necesario utilizar el polimorfismo. Utilice una clase base abstracta con una invocación de método virtual (operator() si por favor), con un descendiente de plantilla que implementa el método virtual utilizando la firma tipo correcto.

La forma en que lo tienes ahora, los datos que llevan a cabo el tipo de plantilla es, pero el código de la intención de invocar el método y pasar el objeto no lo es. Eso no funcionará; los parámetros de tipo plantilla necesitan para fluir a través de la construcción y la invocación.

@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;
}

He intentado esto, pero no funciona (impresión "ok") ... ¿por qué?
Editar Como se ha mencionado Neil Butterworth, el polimorfismo funciona a través de punteros y referencias,

  X x;
  callback& c = callback_specialization<X>(x, &X::y);
  c();

Editar Con este código, me sale un error:

invalid initialization of non-const reference of type ‘callback&’
from a temporary of type ‘callback_specialization<X>’

Ahora, no entiendo ese error, pero si reemplazo de devolución de llamada y c con de devolución de llamada y c const y Virtual operador void () () virtual operador void () () const , funciona.

No dijiste lo que has encontrado errores, pero he encontrado que esto funcionó:

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;

};

Tenga en cuenta que Ptr necesita un constructor, ya que tiene un miembro de referencia.

Se podría prescindir estructura Ptr y tienen los miembros primas.

Probado con VS2008 expresa.

La mejora de la respuesta de la OP:

int main() {
  X x;
  callback_specialization<X> c(x, &X::y);
  callback& ref(c);
  c();
  return 0;
}

Esto imprime "ok".

Probado en VS2008 expresa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top