第7章

  1. 对于每个函数调用,候选集是所有在调用位置可访问的、具有指定名称的函数集合(可访问性可能受到命名空间、嵌套作用域等影响)。
  2. 在给定参数及其类型的情况下,从重载集中选择调用哪个函数的过程。
  3. 对于模板函数和成员函数(以及C++17中的类构造函数),类型推导会根据函数参数的类型来确定模板参数的类型。对于每个参数,可以从多个参数中推导出类型。所以推导结果必须一致,否则类型推导失败。当模板参数类型推导出来,这些具体类型就会替换到所有参数、返回类型和默认参数中的模板参数位置。这就是类型替换。
  4. 如前所述的类型替换可能导致无效类型,例如为没有成员函数的类型生成成员函数指针。此类替换失败不会产生编译错误;相反,失败的重载会从重载集中移除。
  5. 这仅发生在函数声明中(返回类型、参数类型和默认值)。在重载解析选中的函数体内部,发生的替换失败则是硬性错误。
  6. 如果每个重载返回不同的类型,这些类型可以在编译时进行检查。这些类型必须有某种方式来区分它们,例如不同的大小或内嵌常量的不同值。对于 constexpr 函数,还可以检查返回值(这种情况需要函数体)。
  7. 这需要非常小心谨慎地使用。通过故意引发替换失败,可以引导重载解析选择特定的重载。通常,期望的重载会优先选择,除非它失败;否则,变长参数重载会保留并选中,表明想要测试的表达式是无效的。通过使用返回类型来区分重载,可以生成一个可在条件编译中使用的编译时常量(constexpr 常量)。
  8. C++20 约束提供了更自然、更易于理解的语法。当调用函数不满足要求时,还能产生更清晰的错误信息。与 SFINAE 不同,约束不限于函数模板的替换参数。
  9. 标准不仅仅在语言中定义了概念和约束,还提供了一种关于模板限制的思考方式。尽管存在大量基于 SFINAE 的技术,但如果将 SFINAE 的使用限制在少数几种类似于概念使用的强大方法上,代码将更易于阅读和维护。