Google C++ Style Guide 中为什么禁止使用缺省函数参数?

3. 缺省参数(Default Arguments)禁止使用缺省函数参数。 优点:经常用到一个函数带有大量缺省值,偶尔会重写一下这些值,缺省参数为很少…
关注者
260
被浏览
52,133

9 个回答

@黄柏炎

说的完全正确,就是 ABI 的问题。我再补充一点:versioning,特别是基础库和应用程序由不同的团队维护的情况下。

借用他的例子,假设你的应用程序的代码里写了一句:

optimize();

如果事后(程序发布上线运行几周之后)你想知道程序指定的 optimize level 是几,你要么反汇编去看,要么必须察看编译这个应用程序时用的库的头文件(那个 revision snapshot),而不能简单地察看这个库当前的头文件,因为这个缺省值在这段时间可能已经改过了。

如果 A 库定义了带缺省参数的 optimize(),B 库调用了 optimize(),而你的程序使用了 B 库,那么要找出你的程序实际使用的 optimize level,看 B 的源代码是没用的,看 A 现在的源码也没用,你需要察看你的程序用到的那份 B 库(lib或so)在编译的那一刻用的 A 的头文件的源码。

另外,编译器会在每个调用端帮你填上(传入)缺省参数,因此对于某些特别常用的函数,提供短参数的 overload 可以缩小 binary 的体积,例如

code.google.com/p/googl

所言。

最后,带缺省参数的函数的原型(签名)是含有那个参数类型的,例如:

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的