سؤال

لا يعمل التعليمات البرمجية التالية، لكنه يعبر عن ما أريد القيام به. هناك مشكلة في حاوية بنية القالب، والتي أعتقد أنه يجب أن تعمل لأن حجمها معروف بأي حجة قالب.

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;

};

هل هناك أي طريقة للقيام بهذا الشيء؟ يعني لديك رد اتصال فئة غير قالب يلتف أي مؤشر إلى طريقة؟

شكرا G ++ Gurus!

يحرر:

يرجى الاطلاع على هذا:

رد الاتصال في C ++، عضو القالب؟ (2)

هل كانت مفيدة؟

المحلول 7

يرجى الاطلاع على هذا

رد الاتصال في C ++، عضو القالب؟ (2)

نصائح أخرى

هذا مثال عمل كامل يفعل ما أعتقد أنك تحاول القيام به:

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

لقد نفذت مؤخرا هذا:

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

استخدامه مثل ذلك:

حدد:

Event<SomeClass> someEvent;

استضافة عمليات الاسترجاعات:

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

اثار:

someEvent(someClassObj);

يمكنك أيضا جعل المندوبين الخاصين وإدراكهم على ما يفعلونه. لقد قمت ببعض الأشخاص الآخرين الذين لديهم قادرة على التأكد من أن الحدث يثير الوظيفة في مؤشر ترابط واجهة المستخدم الرسومية بدلا من الخيط الذي تم استدعاؤه.

تحتاج إلى استخدام تعدد الأشكال. استخدم فئة قاعدة مجردة مع طريقة استدعاء افتراضية (operator() إذا أرادكت)، مع سليل TEMPLATED الذي ينفذ الطريقة الافتراضية باستخدام توقيع النوع الصحيح.

الطريقة التي لديك الآن، يتم تضمين البيانات التي تمسك بالنوع، ولكن الكود يعني استدعاء الأسلوب ونقل الكائن غير. هذا لن يعمل؛ يحتاج معلمات نوع القالب إلى التدفق من خلال كل من البناء والاحتجاج.

barry كيلي

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

حاولت هذا، لكنها لا تعمل (طباعة "موافق") ... لماذا؟

يحرر:كما ذكرت نيل بتروورث، تعمل تعدد الأشكال من خلال المؤشرات والمراجع،

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

يحرر:مع هذا الرمز، أحصل على خطأ:

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

الآن، أنا لا أفهم هذا الخطأ، ولكن إذا استبدلت معاودة الاتصال و C. مع const callback & c و Void Void المشغل () () مع Void Void المشغل () const, ، إنها تعمل.

أنت لم تقل ما هي الأخطاء التي وجدتها، لكنني وجدت أن هذا عملت:

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;

};

لاحظ أن PTR يحتاج إلى منشئ لأنه يحتوي على عضو مرجعي.

يمكنك القيام به بدون بنية PTR ولديها الأعضاء الخام.

اختبارها مع VS2008 Express.

تحسين إجابة OP:

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

هذه المطبوعات "موافق".

اختبارها على VS2008 Express.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top