1

Event構造体と、構造体によって知られている特定の名前とプロトタイプを持つ関数を実装するオブジェクトが与えられた場合Event、ポインターを返すか、その関数にバインドします。正確に何が返されるかは重要ではありません。それは、メンバー関数へのポインターまたはバインドと同じくらい簡単になります。

説明するのは少し難しいので、ここにいくつかの疑似コードがあります:

struct Foo {
    void onEvent();
};

struct Bar {
    void onEvent();
};

struct Event
{
    // I'm not sure what would go here
    // Needs something that can be used to resolve T::onEvent, without
    // knowing what T is until GetEventFunction is called.
    typedef std::function<void()> function_type;
};

template<typename T, typename EventType>
EventType::function_type GetEventFunction(T* object)
{
    return std::bind(T::(EventType::Something), object);
}

GetEventFunction<Foo, Event>(new Foo); // Returns Foo::onEvent
GetEventFunction<Bar, Event>(new Bar); // Returns Bar::onEvent

この動作を実現できますか、それともC ++が制限されすぎてこれを許可できませんか?

答える前にこれを読んでください

私は反省を探していません。私の知る限り、私が目指していることを実行するために必要なすべての情報は、コンパイル時に利用できます。

また、私は別のアプローチには興味がありません。各イベントタイプのテンプレートの特殊化など、追加のコードを使用してこの動作を実現する多くの方法を知っていますが、これを具体的に実現する方法を探しています。

4

2 に答える 2

4

Eventよく説明できなかったかもしれませんが、関数名はタイプごとに異なります。AFooEventは解決する必要がT::onFooEventあり、aBarEventは解決する必要がありますT::onBarEvent

C ++は型と値を操作できますが、名前は操作できません。これはテキストを処理します。これは、C++本体がコードを確認する前に発生するマクロレベルの処理です。BarEvent型を取得して関数に変換することはできませんT::onBarEvent。これは、それらがたまたま名前が付けられているものを除いて、それらの間に関連付けがないためです。

そのため、Lucの回答では特定の名前が使用されていました。関数の名前はハードコーディングする必要があります。

これで、特性テンプレートを使用して、C++のルールを少し回避できます。たとえば、特定の関数を受け取って呼び出すevent_traitsメンバー関数を持つテンプレートタイプを作成できます。T次のようになります。

template<typename event_type>
struct event_traits
{
  template<typename T> void Dispatch(T *t) {t->DefaultEventFunction();}
};

上記はを使用しDefaultEventFunctionます。

Eventそれぞれに独自のイベント関数を持たせたい場合は、Eventクラスごとに特殊化する必要があります。また、このルールを適用する場合は、オブジェクトを定義DefaultEventFunctionしないでください。Tコンパイラは文句を言います。名前を、のように使用されにくい名前に変更しますWhyDidYouNameThisFunctionLikeThisStopIt

template<>
struct event_traits<FooEvent>
{
  template<typename T> void Dispatch(T *t) {t->onFooEvent();}
};

template<>
struct event_traits<BarEvent>
{
  template<typename T> void Dispatch(T *t) {t->onBarEvent();}
};

ここでマクロが役に立ちます。

#define REGISTER_EVENT_HANDLER(eventName)\
template<> struct event_traits<eventName>\
{\
  template<typename T> void Dispatch(T *t) {t->on ## eventName ();}\
};

したがって、次のようにGetEventFunctionなります。

template<typename T, typename EventType>
EventType::function_type GetEventFunction(T* object)
{
    return std::bind(event_traits<EventType>::Dispatch<T>, object);
}
于 2012-08-10T19:18:06.883 に答える
2

メンバーの名前を知っている場合は、タイプを知る必要はありません。メンバーがオーバーロードされたメンバー関数ではないと仮定します。

template<typename T>
auto GetEventFunction(T& object)
-> decltype( std::bind(&T::onEvent, std::ref(object)) )
{ return std::bind(&T::onEvent, std::ref(object)); }

// Usage:
Foo f;
auto event = GetEventFunction(f);

onEventあなたが言及したことは議論をしないので、これはやや不自然であることに注意してください。もしそうなら、あなたはより多くの足場が必要になるでしょう。mem_fn(とは異なり、オブジェクトも受け入れるaを作成することをお勧めしますstd::mem_fn。)

于 2012-08-10T18:46:42.927 に答える