设foo
函数:
template< typename T >
void foo( T&& a ){}
T
以下调用将推导出什么类型foo
:
foo( 0 ); // is T here int or int&& ?
int a = 0;
foo( a ); // is T here int or int& ?
设foo
函数:
template< typename T >
void foo( T&& a ){}
T
以下调用将推导出什么类型foo
:
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
推导为int
并且par
属于 类型int
。
转发引用通过简单添加一条规则来工作:当用于转发引用(即deduced的参数)T&&
的类型推导的参数是 type 的左值时,使用该类型而不是推导。 T
X
X &
X
请注意,这意味着给定一个 type X
,只有X
或者X &
可以是类型推导的结果;X &&
永远不能。
让我们分析您的代码(我将重命名他的函数参数,以明确我所指的内容):
template <class T>
void foo(T &&par);
foo(0);
int a;
foo(a);
在第一种情况下foo(0)
,参数是类型的右值因此int
类型int
用于类型推导,这意味着T
推导到int
(称为 is 的函数foo<int>
)和类型par
是int &&
。
在第二种情况下foo(a)
,参数是类型的左值int
。转发参考规则启动,类型int &
用于扣除。T
因此推导为int &
(函数称为 is foo<int&>
),类型par
为 " int & &&
",可折叠为int &
。
推断上下文中的表达式T&&
,例如您提供的内容
template< typename T >
void foo( T&& a ){}
即 T 是根据提供的参数推导出来的,受 参考折叠规则的约束。
简而言之;
如果提供的参数是type的左值type
,T&&
将展开为type& &&
折叠为type&
如果提供的参数是type的右值type
,T&&
将扩展为type &&
折叠为type&&
注意两者都是引用,如果需要触发另一个函数的右值重载,需要做std::forward<T>(a)
富(0);// 这里的 T 是 int 还是 int&& ?
一个int
。
整数a = 0;富(一);// 这里的 T 是 int 还是 int& ?
一个int&
。