我在课堂上偶然发现了T&&
,功能意味着不同的东西
在功能:
template<class T> void f(T&& t){}; // t is R or L-value
...
int i=0;
f(i); // t in f is lvalue
f(42); // t in f is rvalue
课堂上:
template<class T>
struct S {
S(T&& t){} // t is only R-value?
};
...
int i;
S<int> ss(i); // compile error - cannot bind lvalue to ‘int&&’
这是否意味着如果我们在课堂上有T&& t
,那么t
只会是右值?
有人可以指出我可以获得更多相关信息吗?
这是否意味着我需要为L和R值写两个方法重载?
ANSWER
正如Alf的例子所示,函数和类中的t
可以是Lvalue或Rvalue。
答案 0 :(得分:9)
你在这里处理模板参数推断。
通过使用f
而不用显式定义模板参数,C ++编译器现在必须从传递它的参数中决定模板参数类型T
是什么。
使用&&
类型的模板参数推导规则是特殊的,以允许完美转发。当您使用f(i)
时,T
会被推断为T&
。因此,参数t
的类型为T& &&
,它会折叠为T&
。但是,当您使用f(42)
时,类型T
会被推断为T&&
,因此t
为T&& &&
,会折叠为T&&
。
一旦强制 T
成为特定类型,所有这些都会有效消失。折叠仍然可能发生,但由于您使用了S<int>
,因此t
将为int&&
类型。 S<int> ss(i)
实际上相当于f<int>(i)
,这也是不合法的。并且由于模板参数推导仅适用于函数而不适用于类型,如果您想要完美转发,则必须对S
执行类似的操作:
template<class T>
struct S {
template<class U>
S(U&& t){}
};
当然,您可以使用SFINAE方法和模板元编程来确保只有T
和U
的基本类型相同才能实例化构造函数模板。
答案 1 :(得分:2)
在你的函数中T
是从实际参数中推导出来的。该特定组合的主要用途是完美转发。在类模板T
中没有推导出来,必须指定它。
例如,这与g ++和msvc很好地编译:
template<class T>
struct S {
S(T&& t){}
};
int main()
{
int i;
S< int& > ss(i);
}