编程C++开发者, 资深开发者

函数模板和带默认参数的类是如何工作的?使用时有哪些细微之处,并且在模板函数与非模板函数之间存在矛盾时该如何处理?

用 Hintsage AI 助手通过面试

答案。

带默认参数的模板是C++中的强大泛化编程机制。

问题的历史:

STL库的起始就是从模板开始的。后来可以为模板函数和类的参数指定默认值,以使模板更加通用并保持代码的可扩展性。

问题:

当存在常规函数和模板函数的重载时,可能会出现不明显的冲突,以及在特化时的模糊性。模板中的默认参数可以提高灵活性,但通常导致复杂的编译错误。

解决方案:

最好最小化模板中默认值的数量,特别是在与非模板版本交叉的情况下。函数调用的优先级更喜欢与常规函数的精确匹配,而不是模板。

示例代码:

template<typename T = int> T multiply(T a, T b = T(2)) { return a * b; } int multiply(int a, int b) { return a + b; }

调用 multiply(5, 4) 会选择函数 int multiply(int, int),而调用 multiply<>(5) 将调用模板,b 将接受值2。

关键特性:

  • 默认值仅在模板的首次声明/定义中声明。
  • 常规函数在匹配签名时优先于模板函数。
  • 只有在显式调用中缺少时,模板参数的默认值才会被应用。

有陷阱的问题。

可以在模板函数的下一个定义中声明默认参数吗?

不可以,默认值只能在一个地方指定(通常在声明中),否则会出现编译错误。

在模板和非模板函数之间存在不明确性时会发生什么?编译器如何选择调用哪个?

如果准确匹配,编译器将始终优先选择非模板函数。仅在没有精确匹配的情况下,模板才会被调用。

可以为模板参数的非类型参数(例如数字)指定默认值吗?

可以,例如:

template<typename T, int N = 8> class Array { T data[N]; };

常见错误和反模式

  • 在多个地方同时声明默认值。
  • 模板和常规函数之间的隐式模糊性。
  • 过度使用默认参数,导致代码难以阅读和调试。

生活中的实例

负面案例

声明了模板函数和非模板函数,具有相同的参数和默认值。在一个模块中调用正常工作,而在另一个模块中意外选择了错误的函数版本。

优点:

  • 方便调用,无需指定类型。

缺点:

  • 不明显的错误和混乱的调用逻辑。

正面案例

对于交叉配置,模板和非模板函数声明了明确不同的名称,只有一个版本具有默认值。

优点:

  • 明确的行为。
  • 没有调用冲突。

缺点:

  • 在维护函数版本时需要更多代码。