理解通用引用的类型推导

Understanding type deduction for universal references

foo为函数:

template< typename T >
void foo( T&& a ){}

以下 foo 的调用将 T 推导出什么类型:

foo( 0 ); // is T here int or int&& ?

int a = 0;
foo( a ); // is T here int or int& ?

类型推导的默认规则是引用类型永远不会是推导的结果。鉴于此代码,

template <class T>
void bar(T par);

bar(0);
int a;
bar(a);
int &b;
bar(b);

所有 3 个调用都会调用 foo<int>。也就是说,T 被推导为 intpar 的类型为 int.

转发引用通过简单添加一个规则来工作:当参数用于转发引用的类型推导时(即参数 T&& 用于 推导 T)是X类型的左值,使用X &类型代替X进行推导。

请注意,这意味着给定一个类型 X,只有 XX & 可以是类型推导的结果; X &&永远不会。

让我们分析一下您的代码(我将重命名函数参数,以明确我指的是什么):

template <class T>
void foo(T &&par);

foo(0);

int a;
foo(a);

在第一种情况foo(0)中,参数是类型int的右值因此类型int用于类型推导,意味着推导Tint(调用的函数是foo<int>)并且par的类型是int &&.

在第二种情况 foo(a) 中,参数是类型 intlvalue。转发引用规则生效,类型 int & 用于推导。 T因此推导为int &(调用的函数为foo<int&>),par的类型为“int & &&”,折叠为int &.

foo( 0 ); // is T here int or int&& ?

一个int.

int a = 0; foo( a ); // is T here int or int& ?

一个int&.

推导上下文中的表达式T&&,就像您提供的那样

template< typename T >
void foo( T&& a ){}

即T是根据提供的参数推导出来的,受制于 reference collapsing rules.

简而言之;

  • 如果提供的参数是左值类型typeT&& 将扩展为 type& && 折叠为 type&

  • 如果提供的参数是 rvalue 类型 typeT&& 将扩展为 type && 折叠为 type&&

注意两者都是references,如果需要触发右值 重载另一个函数,你需要做 std::forward<T>(a)