2012-01-21 2 views
1

EDIT、明確化自分自身を失った:私はオーバーロードされた演算子を使って自分のクラスのEventListenerを使用してのeventHandlersを設定できるようにしたい * >>と私はこの問題は、オーバーロード>>=オペレータがパラメータなeventHandlerとは一致しません、私はそれを正しく宣言する方法がわからないということです*>>オーバーロードされた演算子を使用して新規なeventHandlerを作成しようとすると、必要な構文を理解しようと

それ

ための構文を把握することはできません!私はそれを一致させる場合は

OR

、まともな便利なのEventHandlerオブジェクトにジェネリックTタイプを変換するために必要な情報がを消えた!!宣言ではジェネリック型Tを、ジェネリック型では第二のジェネリック型をパラメータとして混合構文が必要です。

eventHandlerクラスの親を使用すると、efunctorもパラメータ化されていないので無駄です。

例:

リンク>>新なeventHandler(&のApp :: testFunction、アプリ);/*where app is an istance of App class and testFunction is a method of App. */

私はeventHandlerと呼ばれるクラスを持っています。このフォームは、eventHandler<class T>です。今、私は私がこのようにそれを使用できるようにするためにいくつかのクラスの>>オペレータをオーバーロードしたい:アプリケーションが別のクラスで、testFunctionは、明らかに、そのクラスのメソッドである

link >> new eventHandler(&App::testFunction, App); 

。 aboseと書かれた行は、リンクのクラスの>>=オペレータ(便利にはLinkと呼ばれます)への呼び出しを効果的に持つべきです。

私はそれをより明確にするために私のコードの一部を掲載します:

class Link 
{ 
public: 
    eventListener* EventListener; 
    Link() 
    { 
     this->EventListener = new eventListener(); 
    } 

    // PROBLEM 
    // I am lost here, tried different syntaxes but with no success 
    //template<template<class G> class T, class F> 

    template <class T> 
    Link operator>>=(T& ev) 
    { 
     cout << "something"; 
     // Here there is no way to declare the proper eventHandler 
     eventHandler<?>* event = (eventHandler<?>)ev; 
     // I need something like T<F> 
     event->eventName = 'onTest'; 
     this->eventListener->add(event); 
     return *this; 
} 

}; 

template<class T, class F> 
T operator>>(T& lhs, F& rhs) 
{ 
    return T(lhs)>>=rhs; 
} 

class App 
{ 
public: 
    void testFunction(e evt) 
    { 
     cout << "it works!" << "\n"; 
    } 
}; 

int main() 
{ 
    App* app = new App; 
    Link* link = new link; 
    Link link1; 

    eventHandler<App>* ev = new eventHandler<App>(app, &App::testFunction); 
    link1 >> ev;  

    // this line should echo "it works!" 
    link1.EventListener->triggerEvent("onTest"); 

    // PART 2 
    // HOW CAN I USE? 
    // link >> ev; 
    // when link is a Link* 

    return 0; 
} 

私の質問は私の機能のようなものを可能にするように自動的にリンクからメソッドoperator>>=を宣言する方法についてです。

説明: - 右手オペランドとして実際のeventHandlerを持つLinkクラスの>>演算子を使用して、新しいEventHandlerをEventListenerクラスに追加できます。

EDIT 1:

そして、私は2番目の質問を持っている: 私はリンク・クラスへのポインタで呼び出されるように>>オーバーロードされた関数を宣言するためにどのように...私は何ができるかを意味し、私がしたい場合はlink1の代わりにlink>>を使用してください。

Answer Part2:私の推測では、演算子のオーバーロードを使用するためにポインタを間接参照する必要があります。

ANOTHER EDIT

これは、それが少し良く説明するかもしれないコードのバージョンです。私の問題は、コンパイラが失敗した箇所です。>>=オペレータをLinkクラス内でマッチングさせると、そこから問題が解決するかどうか、問題の解決方法が見つからず、イベントシグネチャを保持できません。

そして今、私はより良いコードが自身のために話すましょう:

#include <iostream> 
#include <stdio.h> 
#include "events/events.h" 
using namespace std; 

class Link 
{ 
public: 
    eventListener* EventListener; 

public: 
    Link() 
    { 
     this->EventListener = new eventListener(); 
    } 

    template<class T> 
    Link operator>>=(const T& ev) 
    { 
     ev->eventName = "onReceive"; 
     this->EventListener->add(ev); 
     return *this; 
    } 
}; 

template<class T, class F> 
T operator>>(T& lhs, const F& rhs) 
{ 
    return T(lhs)<<=rhs; 
} 

class App 
{ 
public: 
    void testReceive(e evt) 
    { 
     cout << "it works" << "\n" << evt.value; 
    } 

}; 

class demo 
{ 
public: 
    Link* parent; 
    void testit(char* msg) 
    { 
     parent->EventListener->triggerEvent("onReceive", this, msg); 
    } 
}; 

int main() 
{ 
    App* app = new App; 
    Link link; 

    eventHandler<App>* ev = new eventHandler<App>(app, &App::testReceive); 
    link >> ev; 

    demo d; 
    d.parent = &link; 
    // should output "it works!" 
    d.testit("here"); 

    return 0; 
} 

私も自分のイベントの定義を掲載します:

#ifndef EVENTS_H 
#define EVENTS_H 
#include <stdio.h> 
#include <string.h> 
#include "clist.h" 
#include <string> 

enum scope {global = 0, scoped}; 

struct e 
{ 
    void* target; 
    void* value; 
}; 

class efunctor //abstract 
{ 
public: 
    std::string eventname; 
    virtual void operator()(e evt) 
    { } 

    virtual void Call(e evt) 
    { } 

}; 

template <class T> 
class eventHandler : public efunctor 
{ 
private: 
    T* scope; 
    void (T::*eventMethod)(e); 
public: 
    std::string name; 
    std::string eventname; 
    eventHandler(std::string eventnam, T* objscope, void(T::*func)(e)) 
    { 
     this->scope = objscope; 
     this->eventMethod = func; 
     this->eventname = eventnam; 
    } 

    eventHandler(T* objscope, void(T::*func)(e)) 
    { 
     this->scope = objscope; 
     this->eventMethod = func; 
    } 

    eventHandler(void(T::*func)(e)) 
    { 
     this->eventMethod = func; 
    } 

    void operator()(e evt) 
    { 
     (scope->*eventMethod)(evt); 
    }   

    void Call(e evt) 
    { 
     (scope->*eventMethod)(evt); 
    } 
}; 

class eventListener 
{ 
private: 
    clist< clist<efunctor* > > methods; 
public: 

    template <class T> 
    void add(T other) 
    { 
     other->name = ToString(this->methods[other->eventname].length()); 
     methods[other->eventname][methods[other->eventname].length()] = other; 
    } 

    template <class T> 
    void remove(T other) 
    { 
     methods[other->eventname]->remove(other->name); 
    } 

    template <class F> 
    void triggerEvent(std::string name, void* target, F result) 
    { 
     e evt; 
     evt.target = target; 
     evt.value = (char*)result; 
     for(methods[name].iterateStart(); 
        !methods[name].eoi(); 
        methods[name].next()) 
     { 
      (*(methods[name].getCurrentIteration()))(evt); 
     } 
    } 
}; 
#endif 
+4

あり 'new'とない非常にRAIIの非常に多くがあるか'削除'あなたのコードで。 –

+1

さて、私はそれが最初に働いていることを見て、それから世話したいと思います。 – khael

+2

このようなコードを書き留めたり(共有しないでください)、それは悪い先例を設定します。さらに、私は本当にあなたの問題が何であるかを把握するのに苦労しているので、明確にしたいかもしれません。 – Grizzly

答えて

1

は別にnewの過度の使用からの他のものがありますこのようなことをしようとする前に、概念的に明確にする必要があると思います。 operator>>()をオーバーロードして、適切なメンバーバージョンのoperator>>=()を必要に応じて呼び出すことは実際には問題ありません。これを行う必要はないかもしれません。シフト演算子の左辺引数を制御する場合、をしたい。 std::istreamでは標準のC++ライブラリクラス[テンプレート]を制御できないため、この方法では機能しません。

先に進む前に、最初に追加した質問に答えてみましょう。組み込み型のみを含む演算子はオーバーロードできません。ポインタは組み込み型と見なされます。物語の終わり。とにかくポインタを使用する必要があります。それらは、あるレベルで必要な低レベルの抽象ですが、適切なクラスのオブジェクトを扱うより高いレベルで必要です。これは決して物事を困難にするものではありませんが、物事を楽にします。

あなたのコードでは、突然いくつかのテンプレートテンプレートが表示されます:これはほとんど確実に問題ではなく、あなたの問題の一部です。また、イベントレシーバーに多態性を持たせたい場合は、小さな継承階層が必要です。インターフェースを使用してイベントをトリガーする基本クラスと、少数の仮想関数を実装するテンプレート化された派生クラスを定義しますこのインタフェースによって定義されます。イベントが呼び出されると、ベースは仮想関数を呼び出し、偶数はイベントを受け取ります。これはstd::function<Signature>が効果的に働く方法です。

質問にはあまりにも多くの未定義のものがあり、あなたが望むものを効果的に実装するコード例を使って答えてください。個人的には、私はstd::function<>のモデルに従い、引数としてトリガされるイベントのシグネチャを受け取り、対応するシグネチャを受信者として持つ関数オブジェクトをとるイベントテンプレートを定義します。それは、あなたがこのようなルックスにサブスクライブイベントです:

event<void(std::string)> onTest; 

あなたが何かをするだろうし、これは一般的な使用例であることで呼び出される特定のメンバーを持つオブジェクトを追加したい場合は、あなたが作成することができますあなたは、引数の一定数の機能をサポートする場合は、この簡単に想定し、実装されている。効果的

onTest >> std::bind(std::mem_fn(&App::testFunction), std::ref(app), _1); 

(これは単に簡潔にするためstd::bind()を使用しての線に沿って何かをしてこれを使用するEventHandlerクラステンプレートstd::bind()またはboost::bind()を使用することはできませんが、アリ再実装するbind():これはかなり毛深いものです)。ここで

は私がショーにすべての材料を考える(と私はあなたが実際に可能としたいと思うものを限り近くなる)、完全かつ実施例である:作るような明白な拡張があることを

#include <iostream> 
#include <memory> 
#include <algorithm> 
#include <vector> 

struct event_base 
{ 
    virtual ~event_base() {} 
    virtual void call(std::string const&) = 0; 
}; 

template <typename T> 
struct event: event_base 
{ 
    event(T* o, void (T::*m)(std::string const&)): 
     object(o), 
     member(m) 
    { 
    } 

private: 
    void call(std::string const& arg) { 
     (this->object->*member)(arg); 
    } 
    T* object; 
    void (T::*member)(std::string const&); 
}; 


template <typename T> 
event_base* make_event(T* object, void (T::*member)(std::string const&)) { 
    return new event<T>(object, member); 
} 

class event_listener 
{ 
public: 
    ~event_listener() { std::for_each(events.begin(), events.end(), &deleter); } 
    void add(event_base* event) { this->events.push_back(event); } 
    void trigger(std::string const& argument) const { 
     for (std::vector<event_base*>::const_iterator it(events.begin()), end(events.end()); 
      it != end; ++it) { 
      (*it)->call(argument); 
     } 
    } 

private: 
    static void deleter(event_base* ptr) { delete ptr; } 
    std::vector<event_base*> events; 
}; 

class Link 
{ 
public: 
    event_listener listener; 
    void operator>>= (event_base* ev) { this->listener.add(ev); } 
}; 

void operator<< (Link& link, event_base* ev) { 
    link >>= ev; 
} 

class App 
{ 
public: 
    void onTest(std::string const& arg) { std::cout << "App::onTest(" << arg << ")\n"; } 
}; 

int main() 
{ 
    std::auto_ptr<Link> link(new Link); 
    std::auto_ptr<App> app(new App); 

    *link << make_event(app.get(), &App::onTest); 
    link->listener.trigger("hello event"); 
} 

注意、引数はテンプレート引数を入力します。これは、さまざまな場所でこのテンプレート引数を追加するだけですが、全体的なアプローチは変わりません。

+0

実際に私の問題は、operator >> =は、eventHandlerがクラステンプレートであり、関数呼び出しに到達しないので、私の呼び出しと一致しないということです。だから私は、任意のパラメータと任意のeventHandlerを一致させる演算子のオーバーロードを定義する構文が必要でした。また、eventHandlerはefunctorクラスの継承ですが、それはどちらも役に立ちません。 – khael

+0

指定したコード例に基づいて、すべての詳細をまとめていないという問題があります。これはクラス・テンプレートである 'eventHandler'に関連すると認識しているかもしれませんが、実際の問題は2つのことが必要だということです:1.イベントの呼び出し方法、つまりイベントへの引数機能を登録する前に決定する必要があります。 2.異なるタイプのオブジェクトを保持するために、何らかの形式の消去が必要です。一度に行うための組み込み構文はありません。構築する必要があります。 'std :: function <...>' –

+0

のようなアプローチを使用しています。私は自分のイベントがどのように呼び出されているかを知っています。イベント名の下で、リストの中に「onTest」として格納されています。また、eventListenerのメソッドtriggerEventが、 "そこにあるすべての機能が呼び出されます。私はクラスを自分で作ったので、今は私の要求を処理するのに十分な構文を作り上げようとしています。 – khael

1

私の推測では、あなたはすなわちLink::EventListenerがタイプeventHandlerBase *としてdelcared ...ので、あなたがeventHandlerBaseへのポインタを持つことにより、任意のタイプTのいずれかのeventHandler<T>を参照することができ、あなたのeventHandler<T>eventHandlerBaseのようなクラスから派生させる必要があるということです。

次に、このような何かが働くかもしれない:(。とLink()Link::EventListenerためnew書なし)

template<typename T> 
const link &operator>>=(const eventHandler<T>& ev) 
{ 
    ev->eventName = "onTest"; 
    this->EventListener = &ev; 
} 

+0

あなたの例では、 '>> '演算子はパラメータ化されていて候補と一致しないので、' >> ='演算子とは一致しません。 – khael

関連する問題