类模板与函数模板中的右值引用

时间:2016-09-30 07:13:40

标签: c++ templates rvalue-reference

#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:在函数&#39; int main()&#39;:     main.cpp:20:18:错误:无法绑定&#39; int&#39;左值&#39; int&amp;&amp;&#39;          t(i);                       ^     main.cpp:7:5:注意:初始化&#39; test :: test(T&amp;&amp;)[with T = int]&#39;          测试(T&amp; t)          ^ ~~~

有人可以解释为什么类模板无法编译但功能模板可以吗? 感谢。

2 个答案:

答案 0 :(得分:4)

succeed中,T&& t转发参考,而不是右值参考。但在test中,它是一个右值参考。

仅当参数为T&&T是该函数的模板参数时才会发生转发引用。在您的代码T中是封闭类的模板参数,因此它不会被视为转发引用。

转发引用可以绑定左值和右值。

在起草C ++ 11期间,建议使用不同的语法来转发引用而不是rvalue引用(而不是使用T&& t);然而委员会最终解决了目前的行为。

有关模板参数扣除的更详细说明,包括更精确的T&&何时成为转发参考的说明,see here - 搜索术语&#34;转发参考&#34;找到转发参考的特殊规则。

答案 1 :(得分:3)

您的困惑可能源于您假设T int T。这就是为什么你认为这两种情况类似的原因。实际上他们不是。

在班级版本中,您手动指定T是什么。您明确告诉编译器intT &&。在这种情况下,构造函数参数类型int &&变为T,它不能绑定到常规左值。因此错误。

在函数版本中,您没有告诉编译器T是什么,而是期望编译器推导它。在像您这样的情况下,语言是故意设计为将int &推断为int(注意:不是int &,而是T)。将int &推断为T &&后,所谓的"reference collapsing" rules会导致函数参数类型int &变为i - 一个普通的左值引用。此参数可以成功绑定到左值参数succeed<int>(i);

这解释了你观察到的差异。

为了实验,在后一种情况下,您可以抑制模板参数推导并明确指定模板参数

T

这将强制指定intint &并导致与类版本完全相同的错误,原因完全相同。

同样,您可以通过将模板参数指定为test<int &> t(i);

来“模拟”您的类的函数行为
request.user

相同的“引用折叠”规则将使您的构造函数调用成功编译。

相关问题