6 - 模板参数推导

本文是有关模板参数推导方面知识的补充,补充了有关实参依赖查找(ADL)、万能引用与引用折叠等知识点。

一个模板参数同时只能被推导为一个具体类型

实参依赖查找(ADL)

实参依赖查找(ADL)是一组对函数调用表达式种无限定的函数名进行查找的规则,例如在使用自己编写的max()比较两个string对象时,可能调用的是std::max(),而不是自己编写的max()。如果要用自己编写的,可以这样写:::max()

万能引用与引用折叠

万能引用

也称作转发引用,即 如果接收到左值表达式,那么形参类型推导为左值引用;如果接收到右值表达式,形参类型推导为右值引用

例如:

template<typename T>
void f(T&& t) {}

int a = 10;
f(a);	// a是左值, 接收f<int&>后, T是int&
f(10);  // 10是右值, 接收f<int>后, T是int&&

引用折叠

有时会碰见“引用的引用”这类套娃情况,此时适用 引用折叠(Reference collapsing) 规则,即 右值引用的右值引用折叠成右值引用,所有其他组合均折叠成左值引用。

例如:

// typedef/using中的类型操作(不常见)
using lref = int&;
using rref = int&&;
int n;

lref& r1 = n; // r1 的类型是 int&
lref&& r2 = n; // r2 的类型是 int&
rref& r3 = n; // r3 的类型是 int&
rref&& r4 = 1; // r4 的类型是 int&&
// 模板中的类型操作, 这里直接把 std::forward 定义拿过来了
template <class Ty>
constexpr Ty&& forward(Ty& Arg) noexcept {
    return static_cast<Ty&&>(Arg);
}

int a = 10;
::forward<int>(a);     // 返回 int&&, 因为 Ty 是 int,Ty&& 就是 int&&
::forward<int&>(a);    // 返回 int&, 因为 Ty 是 int&,Ty&& 就是 int&
::forward<int&&>(a);   // 返回 int&&, 因为 Ty 是 int&&,Ty&& 就是 int&&

参考资料

  • 飘零的落花 - 现代C++详解
  • Modern-Cpp-templates-tutorial/md/第一部分-基础知识/01函数模板.md at main · Mq-b/Modern-Cpp-templates-tutorial (github.com)
  • C++20高级编程