C++模板模板参数适配多参数与堆叠策略的实现问题
解决方案:适配策略堆叠与多模板参数的通用参数封装
问题根源
原有实现依赖模板模板参数(仅支持单类型参数的策略模板),无法兼容两种场景:
- 堆叠后的策略是具体实例化类型(而非模板)
- 多参数策略(如
ImposedValueStrategy)包含非类型相关的模板参数(如std::ratio),无法直接适配单参数模板模板参数的要求
核心改造思路
将generic_parameter的模板参数从「模板模板参数」改为「具体策略类型」,同时通过统一策略接口和辅助推导函数实现类型自动推导,避免用户重复显式指定对象类型。
1. 重构通用参数模板
修改generic_parameter,使其接受任意已实例化的策略类型,要求策略必须暴露value_type(关联对象类型)和input_type(输入值类型):
#include <ratio> template <typename Strategy> class generic_parameter { public: using value_type = typename Strategy::value_type; explicit generic_parameter(value_type& obj) : strategy_(obj) {} // 暴露策略核心接口:延迟填充值 void set_value(typename Strategy::input_type val) { strategy_.apply(val); } private: Strategy strategy_; };
2. 统一策略接口定义
所有策略必须实现value_type、input_type和apply方法,确保与generic_parameter兼容。
基础策略示例(BasicStrategy)
template <typename T> class BasicStrategy { public: using value_type = T; using input_type = T; explicit BasicStrategy(T& obj) : obj_(obj) {} void apply(T val) { obj_ = val; } private: T& obj_; };
多参数复杂策略示例(ImposedValueStrategy)
通过绑定器模板预先固定非类型参数(如std::ratio),将多参数策略转换为单参数模板,适配自动推导:
template <typename Ratio, typename T> class ImposedValueStrategy { public: using value_type = T; // 输入值类型为原类型按比例缩放后的类型 using input_type = typename std::ratio_multiply<Ratio, T>::type; explicit ImposedValueStrategy(T& obj) : obj_(obj) {} void apply(input_type val) { obj_ = static_cast<T>(val * Ratio::den / Ratio::num); } private: T& obj_; }; // 绑定器:预先固定Ratio参数,返回仅接受T的单参数模板 template <typename Ratio> struct ImposedValueStrategyBinder { template <typename T> using type = ImposedValueStrategy<Ratio, T>; };
堆叠策略示例(基础策略+比例缩放)
用装饰器模式实现策略堆叠,确保堆叠后的策略仍暴露标准接口:
template <typename InnerStrategy, typename Ratio> class ScalingStrategy { public: using value_type = typename InnerStrategy::value_type; using input_type = typename std::ratio_multiply<Ratio, typename InnerStrategy::input_type>::type; explicit ScalingStrategy(InnerStrategy inner) : inner_(std::move(inner)) {} void apply(input_type val) { using scaled_input = typename InnerStrategy::input_type; inner_.apply(static_cast<scaled_input>(val * Ratio::den / Ratio::num)); } private: InnerStrategy inner_; }; // 辅助函数:自动推导内部策略类型,简化堆叠策略创建 template <typename InnerStrategy, typename Ratio> ScalingStrategy<InnerStrategy, Ratio> scale_strategy(InnerStrategy inner, Ratio) { return ScalingStrategy<InnerStrategy, Ratio>(std::move(inner)); }
3. 辅助推导函数:简化调用
定义make_generic_parameter系列函数,利用C++11模板推导自动生成generic_parameter实例,无需用户显式指定对象类型:
// 适配单参数策略模板(如BasicStrategy) template <template <typename> class Strategy, typename T> generic_parameter<Strategy<T>> make_generic_parameter(T& obj) { return generic_parameter<Strategy<T>>(obj); } // 适配绑定后的多参数策略模板(如ImposedValueStrategyBinder的type) template <template <typename> class Strategy, typename T> generic_parameter<Strategy<T>> make_generic_parameter(T& obj) { return generic_parameter<Strategy<T>>(obj); } // 适配已实例化的堆叠策略 template <typename Strategy> generic_parameter<Strategy> make_generic_parameter(Strategy&& strategy) { return generic_parameter<Strategy>(std::forward<Strategy>(strategy)); }
4. main函数简化调用示例
int main() { double d = 0.0; // 1. 基础策略调用:无需指定double类型 auto param_basic = make_generic_parameter<BasicStrategy>(d); param_basic.set_value(10.0); // d = 10.0 // 2. 多参数策略调用:仅需指定ratio,无需指定double类型 auto param_imposed = make_generic_parameter<ImposedValueStrategyBinder<std::ratio<4,3>>::type>(d); param_imposed.set_value(12.0); // d = 12.0 * 3/4 = 9.0 // 3. 堆叠策略调用:基础策略+2倍缩放,无需手动指定类型 auto scaled_strat = scale_strategy(BasicStrategy<double>(d), std::ratio<2,1>()); auto param_scaled = make_generic_parameter(std::move(scaled_strat)); param_scaled.set_value(5.0); // 内部先转换为5.0*1/2=2.5,再赋值给d return 0; }
内容的提问来源于stack exchange,提问作者J.M
相关产品推荐
相关产品推荐

