如何编写带有默认策略与可变参数的模板?
如何编写带有默认策略与可变参数的模板?
嘿,我看你正在捣鼓一个轻量级的信号/观察者类,目前你已经定义了一个带可变参数的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
相关产品推荐
相关产品推荐

