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

如何实现可适配任意类型函数、API优雅的事件处理机制?

实现自动适配任意函数类型的EventHandler类

可以利用C++的类型擦除、std::function和模板特性,实现一个能自动适配普通函数、类成员函数(含const成员函数)、lambda等各类可调用对象的EventHandler类,无需手动调用std::bind。

核心实现代码

#include <functional>
#include <iostream>
#include <memory>
#include <type_traits>

class EventHandler {
private:
    // 类型擦除基类,统一存储不同类型的可调用对象
    class BaseCallable {
    public:
        virtual ~BaseCallable() = default;
    };

    // 模板子类,封装具体的可调用对象
    template<typename Func>
    class Callable : public BaseCallable {
    public:
        // 支持右值和左值构造
        Callable(Func&& func) : func_(std::forward<Func>(func)) {}
        Callable(const Func& func) : func_(func) {}

        // 完美转发参数调用函数
        template<typename... Args>
        auto operator()(Args&&... args) -> decltype(func_(std::forward<Args>(args)...)) {
            return func_(std::forward<Args>(args)...);
        }

        Func func_;
    };

    std::unique_ptr<BaseCallable> callable_;

    // 辅助函数:创建对应Callable实例并存储
    template<typename Func>
    void set_callable(Func&& func) {
        using DecayedFunc = std::decay_t<Func>;
        callable_ = std::make_unique<Callable<DecayedFunc>>(std::forward<Func>(func));
    }

public:
    // 构造函数1:处理普通函数指针
    template<typename Ret, typename... Args>
    EventHandler(Ret(*func)(Args...)) {
        set_callable(std::function<Ret(Args...)>(func));
    }

    // 构造函数2:处理非const类成员函数,绑定实例
    template<typename Ret, typename Class, typename... Args>
    EventHandler(Ret(Class::*func)(Args...), Class& instance) {
        // 用占位符适配任意数量参数(这里写了6个,可按需扩展)
        set_callable(std::bind(func, &instance, 
            std::placeholders::_1, std::placeholders::_2, 
            std::placeholders::_3, std::placeholders::_4, 
            std::placeholders::_5, std::placeholders::_6));
    }

    // 构造函数3:处理const类成员函数,绑定const实例
    template<typename Ret, typename Class, typename... Args>
    EventHandler(Ret(Class::*func)(Args...) const, const Class& instance) {
        set_callable(std::bind(func, &instance, 
            std::placeholders::_1, std::placeholders::_2, 
            std::placeholders::_3, std::placeholders::_4, 
            std::placeholders::_5, std::placeholders::_6));
    }

    // 构造函数4:通用构造,支持lambda、std::function等可调用对象
    template<typename Func, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Func>, EventHandler>>>
    EventHandler(Func&& func) {
        set_callable(std::forward<Func>(func));
    }

    // 模板调用运算符,完美转发参数
    template<typename... Args>
    auto operator()(Args&&... args) -> decltype(auto) {
        using TargetFunc = std::function<decltype(std::declval<BaseCallable&>().operator()(std::forward<Args>(args)...))(Args...)>;
        return static_cast<Callable<TargetFunc>*>(callable_.get())->operator()(std::forward<Args>(args)...);
    }
};

使用示例

class Abc {
public:
    void aFunc() { std::cout << "a()" << std::endl; }
    void cFunc(int x, char y) { std::cout << "c(" << x << ", " << y << ")" << std::endl; }
    void constFunc() const { std::cout << "constFunc()" << std::endl; }
};

void bFunc(int x) { std::cout << "b(" << x << ")" << std::endl; }

int main() {
    Abc abc;
    const Abc constAbc;

    // 绑定类非const成员函数
    EventHandler a = {&Abc::aFunc, abc};
    // 绑定普通函数
    EventHandler b = bFunc;
    // 绑定带参数的类成员函数
    EventHandler c = {&Abc::cFunc, abc};
    // 绑定const类成员函数
    EventHandler d = {&Abc::constFunc, constAbc};
    // 绑定lambda表达式
    EventHandler e = [](std::string msg) { std::cout << "lambda: " << msg << std::endl; };

    // 调用,参数自动匹配
    a();
    b(123);
    c(456789, 'f');
    d();
    e("hello world");

    std::cout << "Done." << std::endl;
    return 0;
}

关键说明

  1. 类型擦除:通过BaseCallable基类和模板Callable子类,实现对不同类型可调用对象的统一存储,隐藏具体函数类型细节。
  2. 自动绑定:针对成员函数的构造函数会自动调用std::bind绑定对象实例,无需用户手动操作。
  3. 编译期检查:调用EventHandler时,若参数数量/类型与存储的函数不匹配,编译器会直接报错,保证类型安全。
  4. 扩展性:如果需要支持更多参数的函数,只需扩展std::bind中的占位符数量(比如增加到_10)即可。

内容的提问来源于stack exchange,提问作者no one special

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 17:15:15