概览¶
代码生成简单来说就是对一些模板进行简单地字符串替换,生成源代码。在一些大型的项目中,我们也往往会见到一些用工具生成出来的代码。那么,既然 C++ 已经有宏和模板,代码生成的优势在哪里呢?什么时候我们需要使用代码生成?
项目脚手架¶
例如,我们写 C++ 项目,总会需要使用到一些常用库,并且新建类似 src
、include
的文件夹,以及 CMakeLists.txt
等用于构建的文件。另外,当我们写的程序功能上比较相似,比如都是写服务器代码的话,通常也会遵循一定的范式。如果每次写新项目都从头编写这些样本代码,就是浪费时间。这时候我们可以预先编写好一些模板代码,然后使用脚本替换名称等来生成这些基本的脚手架,节约时间。
代码翻译¶
接口描述语言¶
在服务器项目中,我们往往需要使用到接口描述语言(IDL),方便不同语言与服务器进行通信,例如 Protocol Buffers、Thrift 等。这些接口描述语言是独立于所有语言的 DSL,无法直接被引用。这时候就需要生成出对应编程语言的结构体以及辅助函数,这样才能被开发者使用。
SQL 结构转译¶
假如使用了 SQL 数据库,那么可以从数据库中提取表结构,生成对应的结构体定义,也可以生成 IDL 再进一步转译。
项目重构¶
在面临大规模的 API 变动以及项目重构等情况,可以使用代码分析工具先对源代码进行分析,然后做一定变换再输出。
节约重复劳动¶
有时候有一些代码需要有大块的包装函数,这时候使用宏会非常复杂,难以调试;或者是需要跨越多个文件添加代码,例如添加了一个 API,需要对应地添加处理器等;或者是需要生成一些模板没有能力生成的部分,例如生成函数签名等;有的时候生成代码有大量条件判断来生成不同的代码,这时候使用模板就不太灵活。
例如,PyTorch 大量地利用了代码生成来生成 API 以及自动求导代码。
总结¶
代码生成的缺点就是,每次修改了模板代码都要重新生成一次,而且生成出来的代码往往可读性极差。而且如果不将生成的代码提交到版本管理软件的话,开发人员还需要额外安装代码生成工具并运行一次代码生成才能正常浏览和编译项目。另外,代码生成工具往往会覆盖掉已有文件,除了脚手架,一般生成出来的代码是不可以编辑的,当然如果你确定自己在做什么也可以修改,只是需要注意修改不要被下一次的生成给覆盖。
当然,代码生成也有优点,生成的代码一般方便编译器解析,编辑器智能提示相比于宏会更准确。而且在单步调试的时候也会更方便。
大部分时候,都应该使用库或者模板来重用代码,但在必要的时候,例如跨语言共享定义、使用宏或者模板过于复杂、跨文件添加代码或者语言本身根本没有提供宏或者模板的情况下,也可以适当利用代码生成来节约工作量。