我正在開發一種事件系統,其中事件偵聽器在編譯時確定。為了實作這一點,我需要一個函式,它可以告訴我引數是否class T實作了函式的特定特OnEvent()化。
我當前的嘗試使用 C 20requires運算式:
template<class T>
class ScriptComponent
{
static_assert(std::is_base_of_v<Script, T>, "T must derive from Script!");
private:
T m_ScriptInstance;
public:
// Should return true if t.OnEvent<E>(e) can compile, false otherwise.
template<typename E>
constexpr static bool ImplementsEventFunction()
{
constexpr bool isImplemented = requires(const T& t, const E& e)
{
t.OnEvent<E>(e);
};
return isImplemented;
}
};
可以監聽事件的類的示例:
class SomeScript : public Script
{
public:
// delete any non-specialized templates
template<typename E>
void OnEvent(const E&) = delete;
// the template specialization I want to check for
template<>
void OnEvent<SomeEvent>(const SomeEvent& e)
{
// do stuff
}
};
用法ImplementsEventFunction():
// should return true (there is a OnEvent() specialization for SomeEvent)
constexpr bool a = ScriptComponent<SomeScript>ImplementsEventFunction<SomeEvent>();
// should return false (there is no OnEvent() specialization for SomeOtherEvent)
constexpr bool b = ScriptComponent<SomeScript>ImplementsEventFunction<SomeOtherEvent>();
ImplementsEventFunction()無論模板引數是什么,總是回傳 false。顯然,我似乎使用錯誤的 requires 運算式,但我找不到我的錯誤。
uj5u.com熱心網友回復:
沒有理由要求 OnEvent作為模板實作。這感覺像是對用戶代碼的過度控制。概念不是為了告訴用戶如何準確地實作某些東西。您將以某種方式呼叫介面,并且用戶應該實作他們的代碼以使該呼叫語法有效。
你的代碼應該使用t.OnEvent(e). 您的代碼沒有理由需要在呼叫站點顯式指定模板引數。用戶應該能夠將OnEvent某些特定實作E為非模板函式(或多個非模板多載),或者作為模板函式實作模板引數推導處理模板引數。
因此,正確的概念是:
template<typename T, typename E>
concept has_event_for = requires(T t, E e)
{
t.OnEvent(e);
};
class SomeScript : public Script
{
public:
void OnEvent(const SomeEvent& e)
{
// do stuff
}
//No need to delete anything or use templates.
};
不要像對待基類一樣對待概念,在基類中明確說明派生類介面必須嚴格遵循的確切引數。
但是,如果您絕對必須這樣做,則必須template在呼叫站點使用關鍵字:
template<typename T, typename E>
concept has_event_for = requires(T t, E e)
{
t.template OnEvent<E>(e);
};
這是不這樣做的另一個原因。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/532072.html
