Frage

Code Nach nicht funktioniert, aber es drückt auch, was ich tun soll. Es gibt ein Problem mit der Struktur Container-Vorlage, die ich denke, sollten Sie arbeiten, weil es die Größe für Template-Argument bekannt ist.

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;

};

Gibt es eine Möglichkeit, so etwas zu tun? Ich meine, eine Nicht-Template-Klasse Rückruf haben, die alle Zeiger auf Verfahren hüllt?

Danke C ++ Gurus!

Edit:

Bitte beachten Sie folgende:

Rückruf in C ++, Template-Mitglied? (2)

War es hilfreich?

Lösung 7

Andere Tipps

Dies ist ein komplettes Arbeitsbeispiel, das tut, was ich denke, Sie versuchen zu tun:

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

I umgesetzt kürzlich folgt aus:

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

verwenden Sie es wie folgt:

definieren:

Event<SomeClass> someEvent;

Rückrufe gewinnen:

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

Trigger:

someEvent(someClassObj);

Sie können auch Ihre eigenen Delegierten machen und overide was sie tun. Ich habe ein paar andere mit einer um sicherzustellen, dass in der Lage, das Ereignis die Funktion in dem GUI-Thread löst anstelle des Gewindes es hieß.

Sie müssen Polymorphismus verwenden. Verwenden Sie eine abstrakte Basisklasse mit einer virtuellen Aufruf Methode (operator(), wenn Sie bitte), mit einem Templat-Abkömmling, der die virtuelle Methode implementiert die richtige Art Signatur.

So wie du es jetzt haben, sind die Daten, die Art halten templated, aber der Code soll die Methode aufrufen und das Objekt übergeben nicht. Das wird nicht funktionieren; die Vorlage ein Parameter müssen sowohl über die Konstruktion und Anrufung fließen.

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

Ich habe versucht, aber es funktioniert nicht (print "ok") ... warum?
Edit: Als Neil Butter erwähnt, Polymorphismus funktioniert durch Zeiger und Referenzen,

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

Edit: Mit diesem Code, erhalte ich eine Fehlermeldung:

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

Nun, ich verstehe nicht, dass Fehler, aber wenn ich ersetzen Rückruf & c mit const Rückruf & c und virtual void operator () () mit virtual void operator () () const , es funktioniert.

Sie nicht sagen, welche Fehler Sie gefunden, aber ich fand, dass dies funktioniert:

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;

};

Beachten Sie, dass Ptr einen Konstruktor benötigt, da es ein Referenzelement hat.

Sie könnten ohne struct Ptr tun und die rohen Mitglieder haben.

Getestet mit VS2008 Express.

Die Verbesserung der Antwort des OP:

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

Dieses druckt "ok".

Getestet auf VS2008 Express.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top