MST

星途 面试题库

面试题:C++函数模板类型参数替换与SFINAE

已知有函数模板template <typename T> auto func(T t) -> decltype(t + 1) { return t + 1; } 和 template <typename T> std::enable_if_t<!std::is_integral_v<T>, void> func(T t) { /* 空实现 */ }。请解释这两个模板函数的作用,以及在调用func(5)和func(5.5)时,类型参数替换过程是如何遵循SFINAE原则进行的。
26.0万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 模板函数作用解释
    • template <typename T> auto func(T t) -> decltype(t + 1) { return t + 1; }
      • 这个函数模板适用于那些支持与整数 1 相加操作的类型 Tdecltype(t + 1) 用于推导函数的返回类型,它返回 t1 相加后的类型。例如,如果 tint 类型,返回类型就是 int;如果 tdouble 类型,返回类型就是 double
    • template <typename T> std::enable_if_t<!std::is_integral_v<T>, void> func(T t) { /* 空实现 */ }
      • 这个函数模板使用了 std::enable_if 元函数。std::is_integral_v<T> 用于判断类型 T 是否为整数类型。std::enable_if_t<!std::is_integral_v<T>, void> 表示当 T 不是整数类型时,这个模板才是有效的。如果 T 是整数类型,这个模板会被从候选函数集中排除(根据 SFINAE 原则)。此函数实现为空,它主要用于处理非整数类型的情况,虽然当前为空实现,但可以在其中添加对非整数类型的特定处理逻辑。
  2. 类型参数替换过程遵循 SFINAE 原则的分析
    • 调用 func(5)
      • 首先,对于第一个模板 template <typename T> auto func(T t) -> decltype(t + 1) { return t + 1; },当 T 被替换为 int(因为实参 5int 类型)时,decltype(5 + 1) 是有效的,推导返回类型为 int,此模板函数是有效的候选函数。
      • 对于第二个模板 template <typename T> std::enable_if_t<!std::is_integral_v<T>, void> func(T t) { /* 空实现 */ },当 T 被替换为 int 时,std::is_integral_v<int>true,那么 !std::is_integral_v<int>false。根据 std::enable_if 的规则,当条件为 false 时,这个模板函数从候选函数集中被排除(SFINAE 原则)。所以最终调用的是第一个模板函数 func(T t) -> decltype(t + 1),返回 6(因为 5 + 1 = 6)。
    • 调用 func(5.5)
      • 对于第一个模板 template <typename T> auto func(T t) -> decltype(t + 1) { return t + 1; },当 T 被替换为 double(因为实参 5.5double 类型)时,decltype(5.5 + 1) 是有效的,推导返回类型为 double,此模板函数是有效的候选函数。
      • 对于第二个模板 template <typename T> std::enable_if_t<!std::is_integral_v<T>, void> func(T t) { /* 空实现 */ },当 T 被替换为 double 时,std::is_integral_v<double>false,那么 !std::is_integral_v<double>true。所以这个模板函数也是有效的候选函数。由于两个模板函数对于 double 类型都是有效的,但是第一个模板函数有实际的返回值且更具体(因为第二个是空实现),编译器会选择第一个模板函数 func(T t) -> decltype(t + 1),返回 6.5(因为 5.5 + 1 = 6.5)。