簡體   English   中英

我可以在基類模板方法中自動推斷子類型嗎?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM