首先,讓我提供一下上下文。我爲我的遊戲創建了一個小型遊戲框架,我擁有遊戲系統和事件系統。我嘗試使用模板等語言功能來避免用戶代碼中的樣板文件。我可以自動推導基類模板方法中的子類型嗎?
還有Component類,從中派生出其他遊戲元素,即Camera,Sprite,Button。
using EventType = unsigned int;
using EventCallback = std::function<void(Event)>;
class Component {
public:
// This is public version for general functor objects,
// particularly used with lambda
void addHandler(EventType type, const EventCallback &callback);
protected:
// Method for child classes. Creates event handler from method of the class.
//
// This is template method, because std::bind is used for functor creation,
// which requires class type at compile time.
template <class T>
void addHandler(EventType type, void (T::*method)(Event event)) { /*...*/ }
private:
// ...
};
每個組件監聽特定的事件集合,所以它並沒有實現處理程序爲每個可能的事件的類型。此外,組件的用戶應該能夠添加自定義事件偵聽器而不必爲每個遊戲要素創建新類,例如:
class Button : public Component {
public:
Button() {
addHandler(kOnTouch, &Button::onTouch);
}
// ...
};
Button ok, cancel;
ok.addHandler(kOnClick, [](Event) {
// ...
});
cancel.addHandler(kOnClick, [](Event) {
// ...
});
// Add another handler somewhere else in the code
cancel.addHandler(kOnClick, someCallback);
所以,我想要做的是後期綁定,與成員函數編譯時檢查。我想確保傳遞給addHandler()的方法指針屬於調用addHandler()的子類。我可以在template argument deduction的幫助下在addHandler()中獲得類型的方法所有者。但是我沒有找到一種推導孩子班級類型的方法。我在這裏是如何試圖與decltype(*this)
和類型的特徵來實現:
template <class T>
void addHandler(EventType type, void (T::*method)(Event event)) {
/***** This check is INCORRECT *****/
// Check that T is same as child class
using ChildClass = std::remove_reference<decltype(*this)>::type;
static_assert(std::is_same<T, ChildClass>::value,
"Event handler method must belong to caller class");
using namespace std::placeholders;
EventHandler::Callback callback =
std::bind(method, static_cast<T *>(this), _1);
addHandler(EventHandler(type, callback));
}
在這裏我們需要子類類型T搭配比較。看起來ChildClass被分配給基類Component而不是child。有沒有辦法自動推斷子類的類型,只更改方法版本addHandler()?僅對此重載的addHandler()而不是整個Component類進行模板化以使生成的代碼最小化並能夠使用多態性非常重要。所以它是更通用的addHandler()的小包裝,取std :: function。
此刻,我只能檢查T是組件:
static_assert(std::is_base_of<Component, T>::value,
"Event handler method must belong to caller class");
那麼,你需要決定是否要早期或後期綁定使用。如果您想使用早期綁定,請勿使用公共子類。 –
@Let_Me_Be我想遲到(運行時)綁定而不是早期(編譯時),所以用戶代碼可以管理事件處理程序,即在條件語句中。 http://stackoverflow.com/questions/10580/what-is-the-difference-between-early-and-late-binding –