C++ T&&;在模板化函数和类中
我刚刚偶然发现,C++ T&&;在模板化函数和类中,c++,c++11,rvalue-reference,pass-by-rvalue-reference,C++,C++11,Rvalue Reference,Pass By Rvalue Reference,我刚刚偶然发现,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 void f(T&&T){};//t是R或L值 ... int i=0; f(i);//f中的t是左值 f(42);//f中的t
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 void f(T&&T){};//t是R或L值
...
int i=0;
f(i);//f中的t是左值
f(42);//f中的t是右值
课堂上:
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&&’
模板
结构S{
S(T&&T){}//T是唯一的R值吗?
};
...
int i;
S ss(i);//编译错误-无法将左值绑定到“int&&”
这是否意味着如果我们在课堂上有T&&T
,那么T
只会是右值?有人能告诉我在哪里可以得到更多的信息吗?
这是否意味着我需要为L和R值编写两个方法重载 回答
正如Alf的例子所示,函数和类中的
t
可以是左值或右值 函数中的T
是从实际参数推导出来的。该特定组合的主要用途是完美转发。在类模板中,T
未推导,必须指定
例如,这可以很好地与g++和msvc一起编译:
template<class T>
struct S {
S(T&& t){}
};
int main()
{
int i;
S< int& > ss(i);
}
模板
结构S{
S(T&&T){}
};
int main()
{
int i;
Sss(i);
}
函数中的T
是从实际参数推导出来的。该特定组合的主要用途是完美转发。在类模板中,T
未推导,必须指定
例如,这可以很好地与g++和msvc一起编译:
template<class T>
struct S {
S(T&& t){}
};
int main()
{
int i;
S< int& > ss(i);
}
模板
结构S{
S(T&&T){}
};
int main()
{
int i;
Sss(i);
}
这里处理的是模板参数推断
通过使用<代码> f <代码>而不显式定义模板参数,C++编译器现在必须决定模板参数类型<代码> t>代码>是从您传递的参数中得出的。
使用
&&
类型的模板参数推断规则是特殊的,以允许完美的转发。使用f(i)
时,T
被推断为T&
。因此,参数t
的类型为t&&&&
,其折叠为t&
。但是,当您使用f(42)
时,类型T
被推断为T&
,因此T
是T&&&&
,它将折叠为T&&
一旦你强迫T
成为一个特定的类型,所有这些实际上都消失了。折叠仍然可能发生,但由于使用了S
,因此t
的类型将为int&
S ss(i)
实际上等同于f(i)
,这也是不合法的。由于模板参数推导只适用于函数而不适用于类型,因此如果您想要完美的转发,您必须对S
执行以下操作:
template<class T>
struct S {
template<class U>
S(U&& t){}
};
模板
结构S{
样板
S(U&t){}
};
当然,您可以使用SFINAE方法和模板元编程来确保构造函数模板只能在T
和U
的基本类型相同的情况下实例化。这里处理的是模板参数推断
通过使用<代码> f <代码>而不显式定义模板参数,C++编译器现在必须决定模板参数类型<代码> t>代码>是从您传递的参数中得出的。
使用
&&
类型的模板参数推断规则是特殊的,以允许完美的转发。使用f(i)
时,T
被推断为T&
。因此,参数t
的类型为t&&&&
,其折叠为t&
。但是,当您使用f(42)
时,类型T
被推断为T&
,因此T
是T&&&&
,它将折叠为T&&
一旦你强迫T
成为一个特定的类型,所有这些实际上都消失了。折叠仍然可能发生,但由于使用了S
,因此t
的类型将为int&
S ss(i)
实际上等同于f(i)
,这也是不合法的。由于模板参数推导只适用于函数而不适用于类型,因此如果您想要完美的转发,您必须对S
执行以下操作:
template<class T>
struct S {
template<class U>
S(U&& t){}
};
模板
结构S{
样板
S(U&t){}
};
当然,您可以使用SFINAE方法和模板元编程来确保构造函数模板只能在T
和U
的基本类型相同时实例化。T
可以是右值引用或左值引用,但在这两种情况下,T
都是左值。无论类型如何,每个函数参数都是左值。t
可以是右值引用或左值引用,但在这两种情况下,t
都是左值。无论类型如何,每个函数参数都是左值。