类模板与函数模板中的右值引用 [英] rvalue reference in class template vs function template
问题描述
#include <iostream>
template <typename T>
class test
{
public:
test(T&& t)
{
}
};
template <typename T>
void succeed(T&& t)
{
}
int main()
{
int i = 1;
test<int> t(i); // failed to compile
succeed(i); // OK
return 0;
}
来自GCC 5.2的错误:main.cpp:在函数'int main()'中:main.cpp:20:18:错误:无法将'int'左值绑定到'int&&'测试t(i);^main.cpp:7:5:注意:初始化'test :: test(T&&)[with T = int]'的参数1测试(T& t)^ ~~~
Error from GCC 5.2: main.cpp: In function 'int main()': main.cpp:20:18: error: cannot bind 'int' lvalue to 'int&&' test t(i); ^ main.cpp:7:5: note: initializing argument 1 of 'test::test(T&&) [with T = int]' test(T&& t) ^~~~
有人可以解释为什么类模板不能编译但是功能模板可以吗?谢谢.
Could someone explain why the class template cannot compile but function template is OK? Thanks.
推荐答案
您的困惑可能源于您在两种情况下 T
是 int
的假设.这就是为什么您认为这两种情况相似.实际上不是.
Your confusion is probably rooted in your assumption that in both cases T
is int
. This is why you presume that these two cases as similar. In reality they are not.
在类版本中,您手动指定 T
是什么.您明确告诉编译器 T
是 int
.在这种情况下,构造函数参数类型 T&
变为 int&
,它不能绑定到常规左值.因此是错误.
In the class version you are manually specifying what T
is. You explicitly tell the compiler that T
is int
. Constructor parameter type T &&
in this case becomes int &&
, which cannot bind to a regular lvalue. Hence the error.
在函数版本中,您没有告诉编译器 T
是什么,而是希望编译器推断.在像您这样的情况下,该语言被故意设计为将 T
推导出为 int&
(注意:不是 int
,而是int&
).一旦将 T
推导出为 int&
,即所谓的导致函数参数类型 T&
变为 int&
-普通的左值引用.此参数可以成功绑定到左值参数 i
.
In the function version you don't tell the compiler what T
is, but instead you expect the compiler to deduce it. In situations like yours the language is deliberately designed to deduce T
as int &
(note: not as int
, but rather as int &
). Once T
is deduced as int &
, the so called "reference collapsing" rules lead to function parameter type T &&
becoming int &
- an ordinary lvalue reference. This parameter can successfully bind to lvalue argument i
.
这说明了您观察到的差异.
That explains the difference you observe.
为便于实验,在后一种情况下,您可以禁止模板参数推导并显式指定模板参数
For the sake of experiment, in the latter case you can suppress template argument deduction and specify the template argument explicitly
succeed<int>(i);
由于相同的原因,这将强制将 T
指定为 int
,并导致与类版本中相同的错误.
That will forcefully specify T
as int
and lead to the very same error as in the class version for the very same reason.
类似地,您可以通过将模板参数指定为 int&
Similarly, you can "simulate" function's behavior for your class by specifying the template argument as int &
test<int &> t(i);
相同的引用折叠"规则将使您的构造函数调用成功编译.
The same "reference collapsing" rules will make your constructor invocation to compile successfully.
这篇关于类模板与函数模板中的右值引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!