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

如何编写带有默认策略与可变参数的模板?

如何编写带有默认策略与可变参数的模板?

嘿,我看你正在捣鼓一个轻量级的信号/观察者类,目前你已经定义了一个带可变参数的Signal模板接口(为了简化我把实现部分去掉了):

template <typename ... ARGS> class Signal { 
public:     
    void connect(AbstractSlot<ARGS...>& slot);     
    void disconnect(AbstractSlot<ARGS...>& slot);     
    void emit(const ARGS&...args);      
    //... 其他成员逻辑
};

它的基础用法大概是这样的,比如声明一个不带参数的信号:

Signal<> signal1; // 无参信号示例

现在要给这个模板加上默认策略的话,其实很容易实现,核心就是给模板新增一个带默认值的策略参数,同时保留可变参数的灵活性。我给你一步步拆解怎么搞:

  • 首先先定义一个默认的策略类,把那些可以定制的行为封装进去,比如连接时的校验、发射信号时的额外处理等:

    // 默认的信号策略类,封装可定制的行为逻辑
    struct DefaultSignalStrategy {
        // 连接操作的默认处理逻辑
        template <typename SlotType>
        void handleConnect(SlotType& slot) {
            // 这里可以放默认的连接校验、状态记录等逻辑
        }
    
        // 信号发射的默认处理逻辑
        template <typename... Args>
        void handleEmit(const Args&... args) {
            // 默认不做额外处理,直接配合核心逻辑转发信号
        }
    };
    
  • 接着修改你的Signal模板,把策略类型作为新增的模板参数,并且给它设置默认值为我们刚才定义的默认策略:

    // 新增Policy模板参数,默认使用DefaultSignalStrategy
    template <typename ... ARGS, typename Policy = DefaultSignalStrategy> 
    class Signal { 
    private:
        Policy m_strategy; // 持有策略对象,用于调用定制化逻辑
    public:     
        void connect(AbstractSlot<ARGS...>& slot) {
            // 先执行策略类的连接处理逻辑
            m_strategy.handleConnect(slot);
            // 再执行你原本的核心连接逻辑...
        }     
    
        void disconnect(AbstractSlot<ARGS...>& slot) {
            // 你的核心断开连接逻辑...
        }     
    
        void emit(const ARGS&...args) {
            // 先执行策略类的发射处理逻辑
            m_strategy.handleEmit(args...);
            // 再执行你原本的核心信号发射逻辑...
        }      
        //... 其他成员
    };
    

这样调整之后,你原来的用法完全不受影响——当你写Signal<>或者Signal<int, std::string>这类代码时,编译器会自动使用DefaultSignalStrategy作为默认策略。如果需要定制特殊行为,你只需要实现自己的策略类,然后在声明Signal时传入就行:

// 自定义一个带日志输出的策略类
struct LoggingSignalStrategy {
    template <typename SlotType>
    void handleConnect(SlotType& slot) {
        // 连接时打印日志
        std::cout << "Slot已成功连接" << std::endl;
    }

    template <typename... Args>
    void handleEmit(const Args&... args) {
        std::cout << "正在发射信号,参数数量:" << sizeof...(args) << std::endl;
    }
};

// 使用自定义日志策略的信号,指定int类型参数和LoggingSignalStrategy
Signal<int, LoggingSignalStrategy> signalWithLogging;

这种设计的好处很明显:既保留了可变参数模板的灵活性(支持任意数量、任意类型的信号参数),又通过策略模式让信号的行为可以按需定制,而且默认策略的存在让普通场景下的用法不需要额外的模板参数,用起来特别顺手。

备注:内容来源于stack exchange,提问作者Patrick Wright

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 16:54:37