Google C++ Style Guide 中为什么禁止使用缺省函数参数?
9 个回答
说的完全正确,就是 ABI 的问题。我再补充一点:versioning,特别是基础库和应用程序由不同的团队维护的情况下。
借用他的例子,假设你的应用程序的代码里写了一句:
optimize();
如果事后(程序发布上线运行几周之后)你想知道程序指定的 optimize level 是几,你要么反汇编去看,要么必须察看编译这个应用程序时用的库的头文件(那个 revision snapshot),而不能简单地察看这个库当前的头文件,因为这个缺省值在这段时间可能已经改过了。
如果 A 库定义了带缺省参数的 optimize(),B 库调用了 optimize(),而你的程序使用了 B 库,那么要找出你的程序实际使用的 optimize level,看 B 的源代码是没用的,看 A 现在的源码也没用,你需要察看你的程序用到的那份 B 库(lib或so)在编译的那一刻用的 A 的头文件的源码。
另外,编译器会在每个调用端帮你填上(传入)缺省参数,因此对于某些特别常用的函数,提供短参数的 overload 可以缩小 binary 的体积,例如
https://code.google.com/p/google-glog/source/browse/trunk/src/glog/logging.h.in#1172所言。
最后,带缺省参数的函数的原型(签名)是含有那个参数类型的,例如:
void (*fp)() = &optimize; // 错误 error: invalid conversion from ‘int (*)(int)’ to ‘int (*)()’
void (*fpi)(int) = &optimize; // 正确
因此你不能给已有的接口函数添加缺省参数,虽然看起来不需要改调用端,但其实可能会 break client code。
主要问题在于:修改默认参数的值是API compatible,但不是ABI compatible!
默认参数虽然默认,不用显示写出,但其还是函数接口的一部分,如果你修改了默认值,所有的consumer必须重新编译 (默认参数值已被编译进consumer的binary当中),但有的时候,我可能希望能够保持ABI compatibility:
void optimize(int level=3);
或者
void optimize(int level);
void optimize_maximum() {
optimize(3)
}
用户可以直接调用optimize(3),自己显示指定level为3,没有问题
如果有一个非常常用的case,实现类似于默认参数的简洁性,我们可以包一个函数optimize_maximum,但此时里面的参数level不再是接口的一部分,而是实现细节。所以当我把optimize_maximum的实现改成optimize(5)的时候,对用户应该是透明的。也就是说是ABI compatiable的