使用可变参数模板实现泛化函子的代码优化咨询
泛化函子实现优化:解决参数包类型别名与模板冗余问题
我正在阅读Andrei Alexandrescu所著的《Modern C++ Design》,书中第五章提到泛化函子(generalized functors)可作为经典命令模式的替代方案。作为元编程新手,我尝试用现代C++的可变参数模板实现书中的泛化函子思路,但当前代码存在模板参数冗余问题——FUNCTORHANDLER需要单独声明R和Args...,无法直接传入FUNCTOR<R, Args...>作为单个模板参数。我希望优化代码结构,但不知道如何为参数包定义类型别名。
现有实现代码
template <typename R, typename... Args> class FUNCTORIMPLEMENTATION{ public: virtual R operator()(Args&&... args)=0; virtual ~FUNCTORIMPLEMENTATION(){} }; template <typename F, typename P, typename R, typename... Args> class FUNCTORHANDLER : public FUNCTORIMPLEMENTATION<R, Args...>{ private: F functor; public: FUNCTORHANDLER(const F& functor) : functor(functor){} R operator()(Args&&... args){return functor(std::forward<Args>(args)...);} }; template <typename R, typename... Args> class FUNCTOR{ private: FUNCTORIMPLEMENTATION<R, Args...>* implementation; public: template <typename F> FUNCTOR(const F& functor):implementation(new FUNCTORHANDLER<F, FUNCTOR, R, Args...>(functor)){} R operator()(Args&&... args){return (*implementation)(std::forward<Args>(args)...);} }; class TESTFUNCTOR { public: float operator()(int i, double d){ return i+d; } }; int main(){ TESTFUNCTOR functor; FUNCTOR<float, int, double> command(functor); float result=command(1, 1.2); return 0; }
期望的优化结构(存在参数包别名错误)
template <typename R, typename... Args> class FUNCTORIMPLEMENTATION{ public: virtual R operator()(Args&&... args)=0; virtual ~FUNCTORIMPLEMENTATION(){} }; template <typename F, typename P> class FUNCTORHANDLER : public FUNCTORIMPLEMENTATION<typename P::RType, typename P::ArgsType...>{//R and Args should not be in the FUNCTORHANDLER's template list private: F functor; public: FUNCTORHANDLER(const F& functor) : functor(functor){} R operator()(Args&&... args){return functor(std::forward<Args>(args)...);} }; template <typename R, typename... Args> class FUNCTOR{ private: FUNCTORIMPLEMENTATION<R, Args...>* implementation; public: template <typename F> FUNCTOR(const F& functor):implementation(new FUNCTORHANDLER<F, FUNCTOR<R, Args...>>(functor)){} //FUNCTOR<R, Args...> must be passed as a single template parameter R operator()(Args&&... args){return (*implementation)(std::forward<Args>(args)...);} using RType=R; using ArgsType=Args;//this is wrong, I don't know how to type aliase a pack expansion };
改进方案说明
C++无法直接为参数包定义类型别名,但可以通过模板部分特化的方式,直接从传入的FUNCTOR类型中拆解出返回值R和参数包Args...,同时用std::unique_ptr替代裸指针管理内存,避免泄漏。
优化后的完整代码
#include <memory> #include <utility> // 基础抽象类 template <typename R, typename... Args> class FUNCTORIMPLEMENTATION { public: virtual R operator()(Args&&... args) = 0; virtual ~FUNCTORIMPLEMENTATION() = default; }; // 处理具体函子的实现类,通过部分特化拆解FUNCTOR的模板参数 template <typename F, typename P> class FUNCTORHANDLER; template <typename F, typename R, typename... Args> class FUNCTORHANDLER<F, FUNCTOR<R, Args...>> : public FUNCTORIMPLEMENTATION<R, Args...> { private: F functor; public: explicit FUNCTORHANDLER(const F& func) : functor(func) {} R operator()(Args&&... args) override { return functor(std::forward<Args>(args)...); } }; // 泛化函主类 template <typename R, typename... Args> class FUNCTOR { private: std::unique_ptr<FUNCTORIMPLEMENTATION<R, Args...>> implementation; public: // 允许传入任意可调用对象 template <typename F> explicit FUNCTOR(const F& functor) : implementation(std::make_unique<FUNCTORHANDLER<F, FUNCTOR<R, Args...>>>(functor)) {} R operator()(Args&&... args) { return (*implementation)(std::forward<Args>(args)...); } // 让FUNCTORHANDLER可以访问模板参数 template <typename F, typename P> friend class FUNCTORHANDLER; }; // 测试用函子 class TESTFUNCTOR { public: float operator()(int i, double d) { return i + d; } }; int main() { TESTFUNCTOR functor; FUNCTOR<float, int, double> command(functor); float result = command(1, 1.2); return 0; }
关键改进点
- 消除模板冗余:通过
FUNCTORHANDLER的部分特化,直接从FUNCTOR<R, Args...>中拆解出R和Args...,无需在FUNCTORHANDLER模板列表中重复声明。 - 内存安全:用
std::unique_ptr替代裸指针管理动态内存,自动释放资源,彻底消除内存泄漏风险。 - 代码简洁性:
FUNCTORHANDLER仅需两个模板参数(具体函子类型F和泛化函子类型P),完全符合你期望的代码结构。
内容的提问来源于stack exchange,提问作者TylerD007
相关产品推荐
相关产品推荐

