Appearance
模板推导规则(引用折叠、auto、多个参数包)+ 经典题
元编程面试的“测脑回路”区域。目标是能对着一小段推导题说出最终类型,并善用 auto/decltype/引用折叠/完美转发。
一、函数模板推导 vs auto 推导(几乎一致)
两者一致特例:auto 可绑花括号 initializer_list,模板不可。
模板推导核心三条(按形参形式)
cpp
template<typename T> void f1(T); // 传值 → 剥掉引用、剥顶层 const/volatile
template<typename T> void f2(T&); // 引用 → 不剥(保留底层)… 但不剥 const
template<typename T> void f3(T&&); // 万能 → 引用折叠规则 + 转发引用举例:
cpp
const int ci = 1;
f1(ci); // T=int (const 被剥)
f2(ci); // T=const int(保 const,因为我们用的是 ci 的引用)
int x=0;
f3(x); // T=int& (左值 → T=int&,折叠成 int&)
f3(42); // T=int (右值 → T=int&&)二、引用折叠(rules)简记
T& && → T&;T&& & → T&;一旦出现 & 结果就是 &;只有 && && 才是 &&。
这就是万能引用 T&& 能接左值的原因:绑左值时 T 推导为 int&,形参 int& &&折叠成 int&。
三、完美转发(forward)配 forwarding reference
cpp
template <typename T, typename... Args>
T make_(Args&&... args) {
return T(std::forward<Args>(args)...); // 逐个按原左右值传
}要区分 std::move(无条件右值化)与 std::forward(保留原值类别的条件转发)——见 modern-cpp/move-semantics。
四、auto 对应推导(const/引用剥除表)
auto x = expr;——按传值规则(剥引用与顶层 const)。auto& x = expr;——引用形式(不剥 const;绑定 const 对象得 const auto&)。auto&& x——万能。- 数组/函数:
auto退化指针;auto&保留数组。 decltype(expr):原样;括号会影响:decltype((x))因 (x) 是左值表达式 → 得T&。
cpp
int i; const int& cri = i;
auto a = cri; // int(剥引用+const)
auto& r = cri; // const int&
decltype(cri) d; // const int&五、让面试官直呼扎实的几张表
表 A:auto 变量
| 声明 | i 为 const int& | 43(int) | | auto v | int | int | | auto& v | const int& | 非法(不绑右值到左值引用) | | const auto& v | const int& | const int&(绑定临时) | | auto&& v | const int& | int&& |
表 B:f T 推导同 auto。
表 C:decltype(x) vs decltype((x)) vs auto ——剥 vs 原样 vs 有括号
六、pack 推导 / 非推导语境
template<typename T> void f(std::vector<T>)不能由f(v)推导出 T,除非能匹配(从实参匹配其实能,因为 T 在模板参数里)。真正“不能推导”常指:出现在非推导语境(如typename T::X、const T*某些 case、lambda 捕获?实参前),需显式指定。- 例:
template<typename T> void f(typename T::type)——T 从实参无法推导出typename U::type里的 U → 需显式。
七、经典推导题速刷(盖答案)
cpp
template <typename T> void F(T); // p1: T=
template <typename T> void G(T&); // p2:
template <typename T> void H(T&&); // p3:
int x; F(x) ____ G(x) ____ H(x) ____
const int cx; F(cx) ____ G(cx)____ H(cx)=const int&
int* p; F(p) ____ G(p)=int*& H(p)=int*&
int arr[4]; F(arr)=int* G(arr)=int(&)[4] H(arr)=int(&)[4]答案参考:F:X 一律剥 cv/引用(值);G 保留引用形态;H 按折叠。数组在“引用形式”保留数组类型、在“值形式”退化指针。
八、如何答题让考官看出“真懂”
- 先说“模板推导和 auto 机制一致”,建立框架。
- 抓住“剥引用/顶层 cv只在传值时”,这是 90% 陷阱根源。
- 引用折叠只用一条结论“出现 & 即 &”。
- 区别
auto(剥) 与decltype(原样) 与decltype((x))(变 T&)。