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

使用可变参数模板实现泛化函子的代码优化咨询

泛化函子实现优化:解决参数包类型别名与模板冗余问题

我正在阅读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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 04:29:49