news 2026/6/10 15:17:04

模板编程—模板编程处理Partial application

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
模板编程—模板编程处理Partial application

一、Partial application

Partial,大家应该比较熟悉,在模板编程中的偏特化就用这个单词,有过python编程经验的更容易理解。Partial application,大家可以把它称为“偏应用”或“部分应用”。这个名字听上去有点特别,但如果有模板偏特化的知识的就可以顺理成章的明白,可能就是把一些未知的值给定义出来,确实也是如此。
在函数编程中,将一个多参函数的部分参数固定来创建一个较少参数的新函数。大家可以理解为把其中的部分参数“重新”给个“默认值”。如果从数学的角度来看,大家可以看作是对未知参数的一个逐步“消元”的过程。给大家一个python的例程来先入为主一下,这样更容易理解:

fromfunctoolsimportpartial#set functiondeffunc(a,b,c,d):return100*(a+b+c+d)# call partial functionpf=partial(func,1,2,3)pf1=partial(func,1,2)pf2=partial(func,1)#call and printprint(pf(4))# 1000printf(pf1(3,4))#1000printf(pf2(2,3,4))#1000

上面的代码通过partial接口处理有四个参数的函数func,返回一个函数指针pf,其中三个参数已经固定为1,2,3(pf1,pf2类似),这个函数指针只需接受一个参数即可。

二、模板(元)编程实现

在上面的分析说明和python的代码展示中,应该可以很明了的知道什么是Partial application。那么就要引入到C++的模板编程中,那么在模板编程中如何实现Partial application的应用呢?在变参模板函数的应用是不是也是这样一个个的固定参数然后不断的递归处理,那么它也可以改造后应用在Partial application开发中。看下面的例子:

#include<iostream>#include<tuple>template<typename Func,typename...PartialArgs>class Partial__{private:Func f_;std::tuple<PartialArgs...>pArgs_;public:Partial__(Func func,PartialArgs...args):f_(func),pArgs_(args...){}//std::index_sequence_for是 C++14引入的一个模板别名,用于根据给定的类型参数包生成一个 std::index_sequence,其索引数量等于参数包中类型的个数。//例如:std::index_sequence_for<T1, T2, T3> 等价于std::index_sequence<0, 1, 2>template<typename...RestArgs>autooperator()(RestArgs...rArgs)const{returnpartialImpl(std::index_sequence_for<PartialArgs...>{},rArgs...);}private:template<size_t...Id,typename...RestArgs>autopartialImpl(std::index_sequence<Id...>,RestArgs...rArgs)const{returnf_(std::get<Id>(pArgs_)...,rArgs...);}};template<typename Func,typename...PartialArgs>autopartial(Func func,PartialArgs...args){returnPartial__<Func,PartialArgs...>(func,args...);}intmulSum(inta,intb,intc,intd){return10*(a+b+c+d);}intmain(){autopf2=partial(mulSum,1,2);std::cout<<"call pf2 result: "<<pf2(3,4)<<std::endl;autopf3=partial(mulSum,1,2,3);std::cout<<"call pf3 result:"<<pf3(4)<<std::endl;return0;}

也可以模仿python实现使用函数指针,C++中最常用的当然是lambda表达式:

#include<iostream>intsum(inta,intb,intc,intd){returna+b+c+d;}autocreateMul(inta){return[a](intb){returna*b;};}intmain(){//单参数处理autopSum=[](intb,intc,intd){returnsum(1,b,c,d);};std::cout<<"pSum ret: "<<pSum(2,3,4)<<std::endl;//通用autopartial=[](autofunc,auto...partialArgs){return[func,partialArgs...](auto...rArgs){returnfunc(partialArgs...,rArgs...);};};autopSum1=partial(sum,1);std::cout<<"pSum1 ret: "<<pSum1(2,3,4)<<std::endl;//return lambdastd::cout<<"return lambda ,ret:"<<createMul(2)(5)<<std::endl;return0;}

如果在C++20以上,也可以使用Lambda表达式中的模板参数包展开机制:

#include<iostream>#include<utility>template<typename F,typename...Args>autopartialImplFunc(F&&f,Args&&...allArgs){//Lambda表达式捕获列表中展开参数包return[f=std::forward<F>(f),...allArgs=std::forward<Args>(allArgs)](auto&&...rArgs)mutable{returnf(allArgs...,std::forward<decltype(rArgs)>(rArgs)...);};}intmultiply(inta,intb,intc,intd){returna*b*c*d;}intmain(){autofunc=partialImplFunc(multiply,1,2);std::cout<<func(3,4)<<std::endl;return0;}

如果在C++23的环境中则可以使用this指针和std::bind_front接口:

class multiply{public:template<typename M>autooperator()(this M&&myself,inta,intb){returna*b*myself.num_;}intnum_=1;};voidtestCpp23(){multiply demo{10};autofBind=std::bind_front(&multiply::operator(),&demo,10);std::cout<<"fBind ret : "<<fBind(10)<<std::endl;}

上面的代码在前面的文章中都有过分析,包括std::index_sequence等,对C++20中的用法也在注释中进行了说明,如果不明白,大家可参看相关的技术文档即可。
另外,在元编程的应用中,偏特化从某种角度来看也算是一种Partial application应用。另外,也可以使用std::bind函数来模拟实现功能,不过它看起来还是有些与python的实现或者说正常的实现有些不一样。

三、分析说明

Partial application应用一个特点是惰性加载或者说延迟计算,意思就是直到函数最终的调用时才会被执行。正如上面的例子,它可以不断的变换参数的数量,自由的创建函数的变体。即可以理解为创建多个有默认参数的别名同实现函数也可以认为创建多个有重载意义的不同名函数。
这种用法在普通函数编程中,确实意义没有多大,更多还是应用于模板的元编程中。

四、应用场景

新技术的应用,无非就是为了“偷懒”或解决现有技术无法方便解决的问题,Partial application出现也是如此。其应用的场景主要有:

  1. 配置参数和验证处理
    从上面的应用可以发现,在项目的一些配置选项及验证或数据库操作中的参数处理中,它有着广泛的应用可能
  2. 数据计算和数据处理
    这种应用就更加常见了,比如过滤某些特殊的参数的数据(其它都使用默认参数,只有重点的参数过滤);计算中的不同情况的计算(类似于重载)等等
  3. 算法控制
    这个和数据计算有些类似,通过不同的参数实现不同的算法策略
  4. 动态任务管理
    可以实现动态的参数配置来达到不同的任务生成,从而在设计模式、并行编程以及其它一些相应场景下应用

五、例程

下面给出一个简单的例程,用来处理不同的任务:

#include<functional>#include<iostream>#include<map>#include<string>class TaskWrap{public:using Task=std::function<void(TaskWrap&,TaskWrap&)>;voidaddTask(conststd::string&id,Task task){tasks_[id]=task;}voidrunTask(conststd::string&id,TaskWrap&tw){if(tasks_.find(id)!=tasks_.end()){tasks_[id](*this,tw);}}private:std::map<std::string,Task>tasks_;};class TaskGenerator{public:// create task1autocreateTask1(intsign,intowner){return[sign,owner](TaskWrap&tw1,TaskWrap&tw2){std::cout<<"run task1 sign:"<<sign<<std::endl;};}// create task2autocreateTask2(intsign,intowner){return[sign,owner](TaskWrap&tw1,TaskWrap&tw2){std::cout<<"run task2 sign:"<<sign<<std::endl;};}// create task3autocreateTask3(conststd::string&id,intt1,intt2){return[id,t1,t2](TaskWrap&tw1,TaskWrap&tw2){std::cout<<"run task3 id:"<<id<<" and run "<<t1<<" - "<<t2<<std::endl;};}};intmain(){TaskGenerator tg;TaskWrap runner;TaskWrap worker;autohBrush=tg.createTask1(1,2);autohWash=tg.createTask2(5,6);autohDress=tg.createTask3("dress",7,8);runner.addTask("brush",hBrush);runner.addTask("wash",hWash);runner.addTask("dress",hDress);runner.runTask("brush",worker);runner.runTask("wash",runner);runner.runTask("dress",runner);return0;}

六、总结

古人经常说“天下文章一大抄”,这开发语言之间其实也是类似。都是发现某些问题在当前语言无法方便快捷的处理的情况下又创建了一个新的语言。C++的特点就在于其高度的底层性和灵活性,可以模拟实现各种具体的高级语言的特性,这本来是它的优势,但为了实现这些特性,其过程变得相当复杂。这反而让很多开发者认为C++难于掌握,正所谓优势即劣势,这就是事物的两个方面。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 23:04:49

网盘直链下载助手:高效获取下载链接的浏览器插件

网盘直链下载助手&#xff1a;高效获取下载链接的浏览器插件 【免费下载链接】Online-disk-direct-link-download-assistant 可以获取网盘文件真实下载地址。基于【网盘直链下载助手】修改&#xff08;改自6.1.4版本&#xff09; &#xff0c;自用&#xff0c;去推广&#xff0…

作者头像 李华
网站建设 2026/6/10 18:13:47

Lumafly模组管理器:空洞骑士模组管理的最佳解决方案

Lumafly模组管理器&#xff1a;空洞骑士模组管理的最佳解决方案 【免费下载链接】Lumafly A cross platform mod manager for Hollow Knight written in Avalonia. 项目地址: https://gitcode.com/gh_mirrors/lu/Lumafly Lumafly是一款专为《空洞骑士》设计的跨平台模组…

作者头像 李华
网站建设 2026/6/10 13:48:05

AMD Ryzen SMU调试工具终极指南:硬件性能精准调校与系统优化

AMD Ryzen SMU调试工具终极指南&#xff1a;硬件性能精准调校与系统优化 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: http…

作者头像 李华
网站建设 2026/6/10 22:29:16

中小企业AI转型:Qwen2.5-0.5B轻量部署实战

中小企业AI转型&#xff1a;Qwen2.5-0.5B轻量部署实战 在当前人工智能技术快速演进的背景下&#xff0c;中小企业正面临从“是否上AI”向“如何高效用AI”转变的关键阶段。传统大模型往往依赖高昂算力、复杂运维和专业团队&#xff0c;难以适配中小企业的资源现状。而随着轻量…

作者头像 李华
网站建设 2026/6/10 11:47:22

ncmToMp3:3步完成网易云音乐格式转换的终极利器

ncmToMp3&#xff1a;3步完成网易云音乐格式转换的终极利器 【免费下载链接】ncmToMp3 网易云vip的ncm文件转mp3/flac - ncm file to mp3 or flac 项目地址: https://gitcode.com/gh_mirrors/nc/ncmToMp3 还在为网易云VIP下载的音乐只能在特定App中播放而苦恼吗&#xf…

作者头像 李华