类模板与函数模板中的右值引用
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(我);^main.cpp:7:5:注意:初始化'test::test(T&&) [with T = int]'的参数1测试(T&和;t)^ ~ ~ ~
谁能解释为什么类模板不能编译,而函数模板是可以的?谢谢。
在succeed
中,T&& t
是转发引用,而不是右值引用。但在test
中,它是一个右值引用。
只有当参数为T&&
时才会发生转发引用,T
是该函数的模板参数。在您的代码中,T
是封闭类的模板参数,因此它不算作转发引用。
转发引用可以绑定左值和右值。
在c++ 11的起草过程中,建议使用不同的语法来转发引用和右值引用(而不是对两者都使用T&& t
);然而,委员会最终决定采用目前的做法。
关于模板参数推导的更详细的描述,包括T&&
何时成为转发引用的更精确的规范,请参见这里——搜索"转发引用",查找转发引用的特殊规则
您的困惑可能源于您的假设,即在这两种情况下T
都是int
。这就是为什么你认为这两个案例是相似的。事实上,他们不是。
在类版本中,您手动指定T
是什么。您显式地告诉编译器T
是int
。在本例中,构造函数参数类型T &&
变为int &&
,不能绑定到常规左值。因此出现了错误。
在函数版本中,您不告诉编译器T
是什么,而是期望编译器推断出它。在像您这样的情况下,语言被故意设计为将T
推断为int &
(注意:不是int
,而是int &
)。一旦T
被推导为int &
,所谓的"引用崩溃"规则会导致函数参数类型T &&
变成int &
——一个普通的左值引用。该参数可以成功绑定左值参数i
。
这就解释了你观察到的差异。
为了便于实验,在后一种情况下,您可以抑制模板实参的推导并显式指定模板实参
succeed<int>(i);
这将强制指定T
为int
,并导致与类版本中相同的错误,原因完全相同。
int &
来为您的类"模拟"函数的行为。test<int &> t(i);
同样的"引用折叠"规则将使构造函数调用编译成功。
- 具有常量引用参数的函数模板专用化
- C++有什么方法可以在既不调用函数模板也不提供其模板参数的情况下引用函数模板?
- 两个函数模板候选项.将一个参数作为引用后,选择不太专业的模板
- 请参阅在 Visual Studio 2019 中捕获 std::exception 时对函数模板实例化消息的引用
- 我应该通过常量引用还是模板函数中的值传递?
- 为什么 std::函数模板构造函数不使用通用引用?
- 按值和按引用差异的函数模板
- 如何声明接受转发引用并返回引用或副本的函数模板
- 定义重载C++函数模板的原型时,使用其名称引用以前的定义是否合法?
- 专门化采用通用引用参数的函数模板
- C++ 中的函数模板专用化和右值引用
- VS2013无法根据模板参数指定具有通用引用和返回类型的函数模板
- 具有通用引用的成员函数模板不接受左值
- 在具有通用引用参数的函数模板中使用类模板
- 是否可以使函数模板从函数引用中获取“decltype”
- 返回对函数模板的引用
- 在 c++11 中,当参数类型为常量左值引用与非常量左值引用时,函数模板类型推导的工作原理
- 符号引用调用模板类的成员函数时出现的错误
- 具有引用参数的重载函数模板
- 如何创建一个同时接受数组和向量引用的函数模板