2

次のコードは機能しませんが、私がやりたいことをうまく表現しています。テンプレート構造体コンテナに問題があります。これは、テンプレート引数のサイズがわかっているため、機能する必要があると思います。

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 ++の達人に感謝します!

編集:

これを見てください:

C ++でのコールバック、テンプレートメンバー?(2)

4

7 に答える 7

6

これは、あなたがやろうとしていると私が思うことを行う完全な実例です:

#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();
}
于 2009-08-16T12:57:10.117 に答える
4

私は最近これを実装しました:

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

独自のデリゲートを作成して、その機能をオーバーライドすることもできます。イベントが呼び出されたスレッドではなく、GUIスレッドで関数をトリガーすることを確認できるものをいくつか作成しました。

于 2009-08-16T12:20:34.847 に答える
2

ポリモーフィズムを使用する必要があります。operator()正しい型シグネチャを使用して仮想メソッドを実装するテンプレート化された子孫で、仮想呼び出しメソッド (必要に応じて) を持つ抽象基本クラスを使用します。

現在の方法では、型を保持するデータはテンプレート化されていますが、メソッドを呼び出してオブジェクトを渡すためのコードはテンプレート化されていません。それはうまくいきません。テンプレート型パラメーターは、構築と呼び出しの両方を通過する必要があります。

于 2009-08-16T11:10:07.060 に答える
1

@バリー・ケリー

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

これを試しましたが、うまくいきません (print "ok")...なぜですか?

編集: Neil Butterworth が述べたように、ポリモーフィズムはポインターと参照を介して機能します。

  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>’

さて、そのエラーはわかりませんが、callback& cconst callback& cに、virtual void operator()()virtual void operator()() constに置き換えると、機能します。

于 2009-08-16T11:23:15.937 に答える
0

あなたが見つけたエラーについては言いませんでしたが、これが機能することがわかりました:

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 には参照メンバーがあるため、コンストラクターが必要であることに注意してください。

struct Ptr なしで行うことができ、生のメンバーを持つことができます。

VS2008 Express でテスト済み。

于 2009-08-16T11:08:32.773 に答える
0

これを見てください

C++ でのコールバック、テンプレート メンバー? (2)

于 2009-08-16T12:56:14.797 に答える
0

OPの答えを改善する:

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

これにより、「OK」が出力されます。

VS2008 Express でテスト済み。

于 2009-08-16T11:50:05.497 に答える