背景
近期我们在做一个通用AI的项目时使用了UE4引擎,一个同事在阅读源码时发现了这一段代码写的比较“秀”,于是推荐给我,我阅读之后在此记录笔记。
原代码
这一段代码来自Epic Games Unreal Engine 4,其最新版本为: Github 这是一个私有仓库,访问代码可能需要先加入开发组
1 |
|
分析
C++编程语言可以在编译期间确定一个类型是否可以转换为另一个类型,但是它没有提供一个展示这个信息的关键字,如果不加检测的直接使用类型转换操作符(C style转换和 static_cast<>)操作符,则会引起编译器报错。
上面这个代码实现了一个这样的转换检测的类似“编译期运算符”的操作, 可以在编译期获知两个类型是否可转换的关系。
利用 sizeof 和 函数调用编译期绑定的特性
C++ sizeof运算符可以在编译期实现“常量替换” (这里注意sizeof并不总是在编译期就能确定其值)。
C++ 在进行函数调用时,基于编译期函数调用解析(有些资料把它命名为静态多态)的特征,我们在编译时即可确定将要调用哪一个具体函数。这里,就是利用了函数返回值类型不同来在源码层级上确定了到底是调用了哪一个函数,从而反映出目标类型与对照类型的转换关系。
实现的关键代码:
1 |
|
对空指针做一个强制类型转换,解释为From类型指针,然后作为参数调用Test函数, 在代码中,Test有两个实现,其中一个为To*
类型参数, 另一个则为任意类型的泛参。
这个调用在编译期即可确定, 若From类型可以兼容To
类型(即,有继承层级上的直接关系,或者满足隐式转换规则),则uint16 Test(To*)
函数将被绑定, 否则,uint8 Test(...)
函数将被绑定。而这两个函数的返回值类型被sizeof
运算符在编译期捕捉到,并得到长度,使用长度来反映是否可以转换来给Value赋值,从而实现了一个源码级别上的在编译期确定是否兼容的检测运算符。