代换失败不是错误(SFINAE)

概念

SFINAE(Substitution Failure Is Not An Error)意为代换失败不是错误,这是 C++ 模板机制中的一个重要特性。

核心思想
当模板参数推导失败时,编译器不会报错,而是会尝试匹配其他可能的函数或模板。因此,它可以避免不合理的模板实例化,防止不该匹配的类型被错误实例化。
图片1
图片1
PS:非常非常重要!

代换失败的规则

任何导致代换的模板实参不符合 C++ 语法(即非良构)的情况,都会导致代换失败,而不会引发编译错误。

PS:非良构表示不符合 C++ 的基本语法。
图片1

SFINAE 的具体使用

通常,即使不使用 SFINAE,C++ 也会在模板实例化后报错。但 SFINAE 的关键在于:

SFINAE 使得错误发生在实例化前,而非实例化后。
能不实例化就不要实例化,因为某些模板实例化后可能产生难以理解的错误信息。
使用 SFINAE,错误信息会变得更简单,比如 “未找到匹配的重载函数”。
模板实例化本身是有开销的,尤其对于复杂模板而言,实例化可能带来较大编译成本。
图片1

标准库中的 SFINAE —— enable_if_t

标准库中的 std::enable_if_t 是 SFINAE 的典型应用。

在前面的知识点中,我们讨论了对类型的行为要求,例如:

  • 是否具有 type 成员
  • 是否支持加减运算

使用 enable_if 可以为模板增加约束,从而控制哪些类型可以实例化该模板。

PS:本质上,enable_if 是“使得模板可用,如果满足某个条件”。

enable_if_t 的原理

  • enable_if 在第一参数为 true,才会定义 type 成员;
  • 如果第一参数为 false,则 没有 type 成员,从而导致代换失败(SFINAE 机制生效)。
    图片1
    图片1

SFINAE 是 C++ 模板元编程的核心技巧之一,合理使用可以提高代码的可读性和健壮性。