我看到了std::remove_reference
的可能实现,如下所示
template< class T > struct remove_reference {typedef T type;};
template< class T > struct remove_reference<T&> {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};
为什么lvalue
和rvalue reference
有专精?一般模板本身是否足够并删除引用?我在这里感到困惑,因为在T&
或T&&
专业化中,如果我尝试使用::type
,我仍然应该分别获得T&
或T&&
吗?
你能解释为什么我们在移动中向remove_reference<t>::type&&
施放? (是因为参数被命名所以它将被视为移动函数中的左值?)。
另外,你能指出一种方法,我可以找到并打印出这种类型的东西吗?例如,如果它是rvalue
类型int
,那么我应该打印出int&&
已通过? (我一直在使用std::is_same
来手动检查。)
感谢您的时间。
答案 0 :(得分:37)
为什么lvalue和rvalue引用有专门化?
如果只存在主模板,则执行:
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
?
那是因为如果move()
定义如下:
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()
的目的是给你一个右值,无论你输入什么。由于对返回类型为右值引用的函数的函数调用是rvalue,我们真的希望move()
始终返回右值引用。
这就是我们remove_reference<T>::type&&
的原因,因为将&&
附加到非引用类型始终可以保证产生右值引用类型。
你还可以指出一种方法,我可以找出并打印出类型是什么吗?
我不确定这里的“打印”是什么意思。我不知道将类型名称转换为字符串的可移植方式(无论您如何获得该类型)。
另一方面,如果你的目标是确保传递rvalue,你可以使用如下的静态断言:
#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&&)
{
// ...
}
答案 1 :(得分:0)
当您将某个类型视为模板参数时,编译器会搜索最“专业”的特化。如果你传递int&amp;&amp;对于此模板,编译器使用remove_reference<T&&>
版本。一般专业化不能满足您的需求 - 如果您将int&&
传递给一般专业,则输入int&&
如果要打印类型,请使用typeid(some_type).name()