[英]Can I automatically deduce child type in base class template method?
首先,讓我提供一些背景信息。 我正在為我的游戲創建一個小型游戲框架,其中包含游戲系統和事件系統。 我嘗試使用語言功能(例如模板)來避免用戶代碼中的樣板。
有一個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()的子類。 我可以在模板參數推導的幫助下在addHandler()中獲取方法所有者的類型。 但是我沒有找到一種推斷子類類型的方法。 這是我如何嘗試使用decltype(*this)
和traits類型完成此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。 有沒有一種方法可以自動推斷子類類型,僅在method-version addHandler()內部進行更改? 重要的是,僅將此重載的addHandler()而不是整個Component類作為模板,以最小化生成的代碼並能夠使用多態性。 因此,它是更通用的addHandler()的小包裝,采用std :: function。
目前,我只能檢查T是否為Component:
static_assert(std::is_base_of<Component, T>::value,
"Event handler method must belong to caller class");
似乎將ChildClass分配給基本Component類,而不是分配給child。
這里沒有任何東西被“分配”。 濫用術語會造成混淆。
所述類型的this
在基類的成員函數是基類(當然)。
要知道調用者的類型,您需要調用者的this
指針,而不是基類成員函數內的this
指針。 你可以得到this
指針調用者通過要求調用方將它作為參數傳遞:
template <class T, class U>
void addHandler(EventType type, void (T::*method)(Event event), U* that)
然后,您甚至根本不需要靜態斷言,只需將that
綁定到method
注意,如果您確實保留靜態斷言,則可能要使用std::is_base_of
而不是std::is_same
。
或者,您可以擺脫addHandler
重載,只需要派生類型進行綁定即可:
class Button : public Component {
public:
Button() {
addHandler(kOnTouch, [this](Event e) { onTouch(e); });
}
// ...
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.