为什么有左值和右值引用的专业化?
如果仅存在主模板,则执行以下操作:
remove_reference<int&>::type
会给你:
int&
并做:
remove_reference<int&&>::type
会给你:
int&&
这不是你想要的。左值引用和右值引用的特化允许分别从您传递的类型参数中剥离&
和。&&
例如,如果您正在执行以下操作:
remove_reference<int&&>
类型int&&
将与特化指定的模式匹配T&&
,T
为int
。由于特化将类型别名定义type
为T
(在本例中为int
),因此:
remove_reference<int&&>::type
会给你int
。
你能解释一下我们为什么要投remove_reference<t>::type&&
进去move
吗?
这是因为 ifmove()
定义如下:
template<typename T>
T&& move(T&& t) { ... }
// ^^^
// Resolves to X& if T is X& (which is the case if the input has type X
// and is an lvalue)
然后返回类型将是X&
如果参数move()
是类型的左值X
(这就是所谓的“通用引用”)。我们要确保返回类型始终是右值引用。
的目的move()
是为您返回一个右值,无论您输入什么。由于对返回类型为右值引用的函数的函数调用是右值,所以我们真的希望move()
总是返回一个右值引用。
这就是我们这样做的原因remove_reference<T>::type&&
,因为附加&&
到非引用类型总是保证产生右值引用类型。
您还可以指出一种方法,让我可以找出并打印类型是什么?
我不确定您在这里所说的“打印”是什么意思。我知道没有可移植的方式将类型的名称转换为字符串(无论您如何获得该类型)。
另一方面,如果您的目标是确保传递了一个右值,则可以使用如下静态断言:
#include <type_traits>
template<typename T>
void foo(T&&)
{
static_assert(!std::is_reference<T>::value, "Error: lvalue was passed!");
// ...
}
这依赖于这样一个事实,即当X
传递类型的左值时,T
将推断为X&
.
如果您只想产生替换失败,您也可以使用等效的 SFINAE 约束:
#include <type_traits>
template<typename T, typename std::enable_if<
!std::is_reference<T>::value>::type* = nullptr>
void foo(T&&)
{
// ...
}