You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++模板化事件系统中如何实现参数预绑定?

游戏引擎事件系统的参数预绑定实现

我的游戏引擎包含一套事件系统,核心组件为Event与EventCallback,原有实现如下:

原有事件系统代码

Event.h

#ifndef _EVENT_H_
#define _EVENT_H_
#include "EventCallback.h"
#include <vector>

template<typename... Args>
class Event
{
public:
    Event() = default;
    ~Event()
    {
        for (IEventCallback<Args...>* action : m_actions)
            delete action;

        m_actions.clear();
    }

    void AddListener(IEventCallback<Args...>* action)
    {
        m_actions.push_back(action);
    }

    void RemoveListener(IEventCallback<Args...>* action)
    {
        auto position = std::find(m_actions.begin(), m_actions.end(), action);

        if (position == m_actions.end())
            return;

        m_actions.erase(position);

        if(action != nullptr)
            delete action;
    }

    void Trigger(Args... args)
    {
        for (IEventCallback<Args...>* action : m_actions)
        {
            action->Trigger(args...);
        }
    }

private:
    std::vector<IEventCallback<Args...>*> m_actions;
};

#endif

EventCallback.h

#ifndef _EVENTCALLBACK_H_
#define _EVENTCALLBACK_H_

template<typename... Args>
class IEventCallback
{
public:
    virtual bool operator == (IEventCallback* other) = 0;
    virtual void Trigger(Args... args) = 0;
};
 
template<typename T, typename... Args>
class EventCallback : public IEventCallback<Args...>
{    
public:    
    EventCallback(T* instance, void (T::* function)(Args... args))
    {
        m_instance = instance;
        m_function = function;
    }
    virtual void Trigger(Args... args) override
    { 
        if(m_instance != nullptr)
            (m_instance->*m_function)(args...);
    } 
    
    virtual bool operator == (IEventCallback<Args...>* other) override
    {
        EventCallback<T, Args...>* otherEventCallback = dynamic_cast<EventCallback<T, Args...>*>(other);
        if (otherEventCallback == nullptr)
            return false;

        return  (this->m_function == otherEventCallback->m_function) &&
                (this->m_instance == otherEventCallback->m_instance);
    }

private:
    void (T::*m_function)(Args...);
    T* m_instance;
};

#endif

当前使用方式

目前可以按以下方式创建事件并添加监听器:

CameraController* instance = new CameraController();
Event<InputCallbackData> Ongoing;
Ongoing.AddListener(new EventCallback<CameraController, InputCallbackData>(this, &CameraController::MoveRight));

void CameraController::MoveRight(InputCallbackData data)
{
    Vector3D cameraPos = m_cameraComponent->GetWorldPosition();
    Vector3D cameraRight = m_cameraComponent->GetWorldRotation().GetRightDirection();

    m_cameraComponent->SetWorldPosition(cameraPos + cameraRight * movementSpeed);
}

InputCallbackData inputCallbackData = InputCallbackData();
Ongoing.Trigger(inputCallbackData);

需求:实现参数预绑定

希望为EventCallback添加参数预绑定功能,预期用法如下:

CameraController* instance = new CameraController();
Event<InputCallbackData> Ongoing;
Ongoing.AddListener(new EventCallback<CameraController, InputCallbackData>(this, &CameraController::MoveRight, 10));

void CameraController::MoveRight(InputCallbackData data, float speed)
{
    Vector3D cameraPos = m_cameraComponent->GetWorldPosition();
    Vector3D cameraRight = m_cameraComponent->GetWorldRotation().GetRightDirection();

    m_cameraComponent->SetWorldPosition(cameraPos + cameraRight * speed);
}

InputCallbackData inputCallbackData = InputCallbackData();
Ongoing.Trigger(inputCallbackData);

解决方案

修改后的EventCallback.h代码如下:

#ifndef _EVENTCALLBACK_H_
#define _EVENTCALLBACK_H_
#include <functional>

template<typename... Args>
class ICallback
{
public:
    virtual void Call(Args... args) = 0;
};


template<typename... Args>
class IEventCallback
{
public:
    virtual bool operator == (IEventCallback* other) = 0;
    virtual void Trigger(Args... args) = 0;
};
 
template<typename T, typename... Args>
class EventCallback : public IEventCallback<Args...>
{    
public:    
    template <typename... ExtraArgs>
    EventCallback(T* instance, void (T::*function)(Args..., ExtraArgs...), const ExtraArgs&... extra_args)
    {
        class MethodWrapper : public ICallback<Args...> 
        {
        public:
            MethodWrapper(T* instance, void (T::* function)(Args..., ExtraArgs...), const ExtraArgs&... extra_args)
                : m_instance(instance), m_function(function), m_extra_args(std::make_tuple(extra_args...))
            {}

            virtual void Call(Args... args) override
            {
                // 将元组展开为可变参数模板函数的参数
                std::apply([&](const ExtraArgs&... extra_args) {
                    (m_instance->*m_function)(args..., extra_args...);
                    }, m_extra_args);
            }

        private:
            T* m_instance;
            void (T::* m_function)(Args... args, ExtraArgs...);
            std::tuple<ExtraArgs...> m_extra_args;
        };

        m_callback = std::make_unique<MethodWrapper>(instance, function, extra_args...);
    }
    virtual void Trigger(Args... args) override
    { 
        m_callback->Call(args...);
    } 
    
    virtual bool operator == (IEventCallback<Args...>* other) override
    {
        EventCallback<T, Args...>* otherEventCallback = dynamic_cast<EventCallback<T, Args...>*>(other);

        return otherEventCallback->m_callback == m_callback;

    }


private:    

    std::unique_ptr<ICallback<Args...>> m_callback;

};

#endif

内容的提问来源于stack exchange,提问作者mar ben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 00:07:36