2012-08-10 22 views
1

給定一個Event結構和一個對象,該對象實現了一個具有特定名稱和原型的函數,該函數結構爲Event,我想返回一個指針或綁定到該函數。究竟它返回的並不重要;它可以像指向成員函數或綁定一樣容易。給定一個T和函數名稱和類型,如何解析T :: function?

這是一個有點難以解釋,所以這裏的一些僞代碼:

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++太有限允許這樣做?

請回答

我不是在尋找反射之前閱讀。據我所知,所有需要做的事情都是在編譯時提供的。

另外,我對替代方法不感興趣。我知道有很多方法可以通過額外的代碼實現這種行爲,比如每種事件類型的模板特化,但我正在尋找一種專門實現這一點的方法。

+1

不能完成。我想* C++對你來說太有限了。 – 2012-08-10 18:22:02

+2

你聲稱你對替代品不感興趣,但我仍然說你可能正在遭受XY問題的困擾。特別是考慮你試圖用什麼是範圍解析運算符來表達什麼,它使用標識符而不是類型。 – 2012-08-10 18:26:13

+0

我有100個'Event'結構。我有一個'EventHandler '對象,當事件'T'被引發時,給它一個回調函數。我希望能夠傳遞一個對象,並讓編譯器爲我解析'T :: onEventType'。 – 2012-08-10 18:29:15

回答

4

也許我沒有解釋好,但是功能的名稱是每個Event類型獨特。 A FooEvent應解析T::onFooEvent,而BarEvent應解析T::onBarEvent

C++可以對類型和值進行操作,但不能對的名稱進行操作。這涉及到文本,這是C++本身在查看代碼之前發生的宏觀事件。您不能使用BarEvent類型,並將其轉換爲函數T::onBarEvent,因爲它們之間沒有關聯,除了它們碰巧是的名稱爲

這就是爲什麼Luc的答案使用了一個特定的名稱:函數的名稱必須是硬編碼的。

現在,您可以通過使用traits模板來調整C++的規則。例如,您可以創建一個event_traits模板類型,該模板類型具有一個成員函數,它需要T並調用其上的特定函數。它看起來是這樣的:

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

上述用途DefaultEventFunction

如果您希望每個Event都有其自己的事件功能,則需要針對每個Event類進行專門化。如果您想要執行此規則,則不要在您的任何T對象中定義DefaultEventFunction;編譯器會抱怨。將名稱更改爲不太可能使用的名稱,如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); 
} 
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也接受一個對象,不像std::mem_fn。)

+0

也許我沒有解釋清楚,但函數名稱對於每個'Event'類型都是唯一的。 'FooEvent'應該解析'T :: onFooEvent',而'BarEvent'應該解析'T :: onBarEvent'。 – 2012-08-10 18:52:31

相關問題